2014-12-30 22:36:03 +02:00
|
|
|
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
2012-12-03 16:48:01 -08:00
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2014-12-30 22:36:03 +02:00
|
|
|
// 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
|
2015-06-09 16:26:21 -04:00
|
|
|
// - doesn't own a box
|
2014-12-30 22:36:03 +02:00
|
|
|
//
|
|
|
|
// - For each *immutable* static item, it checks that its **value**:
|
2015-06-09 16:26:21 -04:00
|
|
|
// - doesn't own a box
|
2014-12-30 22:36:03 +02:00
|
|
|
// - 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
|
2013-05-17 15:28:44 -07:00
|
|
|
|
2016-01-21 10:52:37 +01:00
|
|
|
use rustc::dep_graph::DepNode;
|
2016-07-21 07:01:14 +05:30
|
|
|
use rustc::ty::cast::CastKind;
|
2016-03-30 13:43:36 +02:00
|
|
|
use rustc_const_eval::{ConstEvalErr, lookup_const_fn_by_id, compare_lit_exprs};
|
|
|
|
use rustc_const_eval::{eval_const_expr_partial, lookup_const_by_id};
|
2016-04-26 14:10:07 +02:00
|
|
|
use rustc_const_eval::ErrKind::{IndexOpFeatureGated, UnimplementedConstVal, MiscCatchAll, Math};
|
2016-04-26 14:11:14 +02:00
|
|
|
use rustc_const_eval::ErrKind::{ErroneousReferencedConstant, MiscBinaryOp, NonConstPath};
|
|
|
|
use rustc_const_eval::ErrKind::UnresolvedPath;
|
2016-03-30 13:43:36 +02:00
|
|
|
use rustc_const_eval::EvalHint::ExprTypeChecked;
|
2016-04-26 14:10:07 +02:00
|
|
|
use rustc_const_math::{ConstMathErr, Op};
|
2016-09-15 00:51:46 +03:00
|
|
|
use rustc::hir::def::{Def, CtorKind};
|
2016-03-29 12:54:26 +03:00
|
|
|
use rustc::hir::def_id::DefId;
|
2016-01-21 10:52:37 +01:00
|
|
|
use rustc::middle::expr_use_visitor as euv;
|
|
|
|
use rustc::middle::mem_categorization as mc;
|
|
|
|
use rustc::middle::mem_categorization::Categorization;
|
2016-03-22 17:30:57 +02:00
|
|
|
use rustc::ty::{self, Ty, TyCtxt};
|
2016-06-30 21:22:47 +03:00
|
|
|
use rustc::traits::Reveal;
|
2016-07-20 00:02:56 +03:00
|
|
|
use rustc::util::common::ErrorReported;
|
2016-01-21 10:52:37 +01:00
|
|
|
use rustc::util::nodemap::NodeMap;
|
|
|
|
use rustc::middle::const_qualif::ConstQualif;
|
|
|
|
use rustc::lint::builtin::CONST_ERR;
|
2012-12-23 17:41:37 -05:00
|
|
|
|
2016-03-29 08:50:44 +03:00
|
|
|
use rustc::hir::{self, PatKind};
|
2014-09-13 20:10:34 +03:00
|
|
|
use syntax::ast;
|
2016-06-21 18:08:13 -04:00
|
|
|
use syntax_pos::Span;
|
2016-03-29 08:50:44 +03:00
|
|
|
use rustc::hir::intravisit::{self, FnKind, Visitor};
|
2013-08-13 02:10:10 +02:00
|
|
|
|
2015-01-29 13:57:06 +02:00
|
|
|
use std::collections::hash_map::Entry;
|
2015-06-30 08:53:50 -07:00
|
|
|
use std::cmp::Ordering;
|
2015-01-29 13:57:06 +02:00
|
|
|
|
2015-11-17 17:51:44 -05:00
|
|
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
2014-12-30 22:36:03 +02:00
|
|
|
enum Mode {
|
2015-01-29 13:57:06 +02:00
|
|
|
Const,
|
2015-02-25 22:06:08 +02:00
|
|
|
ConstFn,
|
2015-01-29 13:57:06 +02:00
|
|
|
Static,
|
|
|
|
StaticMut,
|
|
|
|
|
|
|
|
// An expression that occurs outside of any constant context
|
|
|
|
// (i.e. `const`, `static`, array lengths, etc.). The value
|
|
|
|
// can be variable at runtime, but will be promotable to
|
|
|
|
// static memory if we can prove it is actually constant.
|
|
|
|
Var,
|
2014-12-30 22:36:03 +02:00
|
|
|
}
|
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
struct CheckCrateVisitor<'a, 'tcx: 'a> {
|
2016-05-03 05:23:22 +03:00
|
|
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
2014-12-30 22:36:03 +02:00
|
|
|
mode: Mode,
|
2015-01-29 13:57:06 +02:00
|
|
|
qualif: ConstQualif,
|
2016-07-21 07:01:14 +05:30
|
|
|
rvalue_borrows: NodeMap<hir::Mutability>,
|
2013-08-13 02:10:10 +02:00
|
|
|
}
|
|
|
|
|
2016-05-11 04:14:41 +03:00
|
|
|
impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
|
2016-07-21 07:01:14 +05:30
|
|
|
fn with_mode<F, R>(&mut self, mode: Mode, f: F) -> R
|
|
|
|
where F: FnOnce(&mut CheckCrateVisitor<'a, 'gcx>) -> R
|
2014-12-08 20:26:43 -05:00
|
|
|
{
|
2015-01-29 13:57:06 +02:00
|
|
|
let (old_mode, old_qualif) = (self.mode, self.qualif);
|
2014-12-30 22:36:03 +02:00
|
|
|
self.mode = mode;
|
2015-04-29 14:58:43 -07:00
|
|
|
self.qualif = ConstQualif::empty();
|
2015-01-29 13:57:06 +02:00
|
|
|
let r = f(self);
|
|
|
|
self.mode = old_mode;
|
|
|
|
self.qualif = old_qualif;
|
|
|
|
r
|
|
|
|
}
|
|
|
|
|
2016-07-21 07:01:14 +05:30
|
|
|
fn with_euv<F, R>(&mut self, item_id: Option<ast::NodeId>, f: F) -> R
|
|
|
|
where F: for<'b, 'tcx> FnOnce(&mut euv::ExprUseVisitor<'b, 'gcx, 'tcx>) -> R
|
2015-01-29 13:57:06 +02:00
|
|
|
{
|
|
|
|
let param_env = match item_id {
|
|
|
|
Some(item_id) => ty::ParameterEnvironment::for_item(self.tcx, item_id),
|
2016-07-21 07:01:14 +05:30
|
|
|
None => self.tcx.empty_parameter_environment(),
|
2015-01-29 13:57:06 +02:00
|
|
|
};
|
2015-06-28 23:03:47 -07:00
|
|
|
|
2016-07-21 07:01:14 +05:30
|
|
|
self.tcx
|
2016-06-30 21:22:47 +03:00
|
|
|
.infer_ctxt(None, Some(param_env), Reveal::NotSpecializable)
|
2016-07-21 07:01:14 +05:30
|
|
|
.enter(|infcx| f(&mut euv::ExprUseVisitor::new(self, &infcx)))
|
2015-01-29 13:57:06 +02:00
|
|
|
}
|
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
fn global_expr(&mut self, mode: Mode, expr: &hir::Expr) -> ConstQualif {
|
2015-01-29 13:57:06 +02:00
|
|
|
assert!(mode != Mode::Var);
|
|
|
|
match self.tcx.const_qualif_map.borrow_mut().entry(expr.id) {
|
|
|
|
Entry::Occupied(entry) => return *entry.get(),
|
|
|
|
Entry::Vacant(entry) => {
|
|
|
|
// Prevent infinite recursion on re-entry.
|
2015-04-29 14:58:43 -07:00
|
|
|
entry.insert(ConstQualif::empty());
|
2015-01-29 13:57:06 +02:00
|
|
|
}
|
|
|
|
}
|
2016-04-01 09:19:29 +02:00
|
|
|
if let Err(err) = eval_const_expr_partial(self.tcx, expr, ExprTypeChecked, None) {
|
|
|
|
match err.kind {
|
2016-07-21 07:01:14 +05:30
|
|
|
UnimplementedConstVal(_) => {}
|
|
|
|
IndexOpFeatureGated => {}
|
|
|
|
ErroneousReferencedConstant(_) => {}
|
|
|
|
_ => {
|
|
|
|
self.tcx.sess.add_lint(CONST_ERR,
|
|
|
|
expr.id,
|
|
|
|
expr.span,
|
|
|
|
format!("constant evaluation error: {}. This will \
|
|
|
|
become a HARD ERROR in the future",
|
|
|
|
err.description().into_oneline()))
|
|
|
|
}
|
2016-04-01 09:19:29 +02:00
|
|
|
}
|
|
|
|
}
|
2015-01-29 13:57:06 +02:00
|
|
|
self.with_mode(mode, |this| {
|
|
|
|
this.with_euv(None, |euv| euv.consume_expr(expr));
|
|
|
|
this.visit_expr(expr);
|
|
|
|
this.qualif
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2015-02-25 22:06:08 +02:00
|
|
|
fn fn_like(&mut self,
|
2015-08-26 12:00:14 +02:00
|
|
|
fk: FnKind,
|
2015-07-31 00:04:06 -07:00
|
|
|
fd: &hir::FnDecl,
|
|
|
|
b: &hir::Block,
|
2015-02-25 22:06:08 +02:00
|
|
|
s: Span,
|
|
|
|
fn_id: ast::NodeId)
|
|
|
|
-> ConstQualif {
|
|
|
|
match self.tcx.const_qualif_map.borrow_mut().entry(fn_id) {
|
|
|
|
Entry::Occupied(entry) => return *entry.get(),
|
|
|
|
Entry::Vacant(entry) => {
|
|
|
|
// Prevent infinite recursion on re-entry.
|
2015-05-05 08:47:04 -04:00
|
|
|
entry.insert(ConstQualif::empty());
|
2015-02-25 22:06:08 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let mode = match fk {
|
2016-08-26 19:23:42 +03:00
|
|
|
FnKind::ItemFn(_, _, _, hir::Constness::Const, ..)
|
2016-08-10 16:20:12 -07:00
|
|
|
=> Mode::ConstFn,
|
2016-08-26 19:23:42 +03:00
|
|
|
FnKind::Method(_, m, ..) => {
|
2015-07-31 00:04:06 -07:00
|
|
|
if m.constness == hir::Constness::Const {
|
2015-02-25 22:06:08 +02:00
|
|
|
Mode::ConstFn
|
|
|
|
} else {
|
|
|
|
Mode::Var
|
|
|
|
}
|
|
|
|
}
|
2016-07-21 07:01:14 +05:30
|
|
|
_ => Mode::Var,
|
2015-02-25 22:06:08 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
let qualif = self.with_mode(mode, |this| {
|
|
|
|
this.with_euv(Some(fn_id), |euv| euv.walk_fn(fd, b));
|
2016-07-28 05:58:45 -04:00
|
|
|
intravisit::walk_fn(this, fk, fd, b, s, fn_id);
|
2015-02-25 22:06:08 +02:00
|
|
|
this.qualif
|
|
|
|
});
|
|
|
|
|
|
|
|
// Keep only bits that aren't affected by function body (NON_ZERO_SIZED),
|
|
|
|
// and bits that don't change semantics, just optimizations (PREFER_IN_PLACE).
|
2015-05-05 08:47:04 -04:00
|
|
|
let qualif = qualif & (ConstQualif::NON_ZERO_SIZED | ConstQualif::PREFER_IN_PLACE);
|
2015-02-25 22:06:08 +02:00
|
|
|
|
|
|
|
self.tcx.const_qualif_map.borrow_mut().insert(fn_id, qualif);
|
|
|
|
qualif
|
|
|
|
}
|
|
|
|
|
2015-01-29 13:57:06 +02:00
|
|
|
fn add_qualif(&mut self, qualif: ConstQualif) {
|
|
|
|
self.qualif = self.qualif | qualif;
|
|
|
|
}
|
|
|
|
|
2015-02-25 22:06:08 +02:00
|
|
|
/// Returns true if the call is to a const fn or method.
|
2016-07-21 07:01:14 +05:30
|
|
|
fn handle_const_fn_call(&mut self, _expr: &hir::Expr, def_id: DefId, ret_ty: Ty<'gcx>) -> bool {
|
2016-03-30 13:43:36 +02:00
|
|
|
if let Some(fn_like) = lookup_const_fn_by_id(self.tcx, def_id) {
|
2015-02-25 22:06:08 +02:00
|
|
|
let qualif = self.fn_like(fn_like.kind(),
|
|
|
|
fn_like.decl(),
|
|
|
|
fn_like.body(),
|
|
|
|
fn_like.span(),
|
|
|
|
fn_like.id());
|
|
|
|
self.add_qualif(qualif);
|
|
|
|
|
2015-06-25 23:42:17 +03:00
|
|
|
if ret_ty.type_contents(self.tcx).interior_unsafe() {
|
2015-05-05 08:47:04 -04:00
|
|
|
self.add_qualif(ConstQualif::MUTABLE_MEM);
|
2015-02-25 22:06:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
true
|
|
|
|
} else {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
fn record_borrow(&mut self, id: ast::NodeId, mutbl: hir::Mutability) {
|
2015-01-29 13:57:06 +02:00
|
|
|
match self.rvalue_borrows.entry(id) {
|
|
|
|
Entry::Occupied(mut entry) => {
|
|
|
|
// Merge the two borrows, taking the most demanding
|
|
|
|
// one, mutability-wise.
|
2015-07-31 00:04:06 -07:00
|
|
|
if mutbl == hir::MutMutable {
|
2015-01-29 13:57:06 +02:00
|
|
|
entry.insert(mutbl);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Entry::Vacant(entry) => {
|
|
|
|
entry.insert(mutbl);
|
|
|
|
}
|
|
|
|
}
|
2013-08-13 02:10:10 +02:00
|
|
|
}
|
2014-09-12 13:10:30 +03:00
|
|
|
}
|
|
|
|
|
2014-09-10 01:54:36 +03:00
|
|
|
impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
|
2015-07-31 00:04:06 -07:00
|
|
|
fn visit_item(&mut self, i: &hir::Item) {
|
2015-06-17 09:56:27 +03:00
|
|
|
debug!("visit_item(item={})", self.tcx.map.node_to_string(i.id));
|
2015-11-17 17:51:44 -05:00
|
|
|
assert_eq!(self.mode, Mode::Var);
|
2015-01-04 17:58:56 +02:00
|
|
|
match i.node {
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ItemStatic(_, hir::MutImmutable, ref expr) => {
|
2016-02-09 21:30:52 +01:00
|
|
|
self.global_expr(Mode::Static, &expr);
|
2014-12-30 22:36:03 +02:00
|
|
|
}
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ItemStatic(_, hir::MutMutable, ref expr) => {
|
2016-02-09 21:30:52 +01:00
|
|
|
self.global_expr(Mode::StaticMut, &expr);
|
2014-12-30 22:36:03 +02:00
|
|
|
}
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ItemConst(_, ref expr) => {
|
2016-02-09 21:30:52 +01:00
|
|
|
self.global_expr(Mode::Const, &expr);
|
2015-01-04 17:58:56 +02:00
|
|
|
}
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ItemEnum(ref enum_definition, _) => {
|
2015-01-29 13:57:06 +02:00
|
|
|
for var in &enum_definition.variants {
|
|
|
|
if let Some(ref ex) = var.node.disr_expr {
|
2016-02-09 21:30:52 +01:00
|
|
|
self.global_expr(Mode::Const, &ex);
|
2015-01-04 17:58:56 +02:00
|
|
|
}
|
2015-01-29 13:57:06 +02:00
|
|
|
}
|
2015-01-04 17:58:56 +02:00
|
|
|
}
|
2014-12-30 22:36:03 +02:00
|
|
|
_ => {
|
2015-11-17 17:51:44 -05:00
|
|
|
intravisit::walk_item(self, i);
|
2014-12-30 22:36:03 +02:00
|
|
|
}
|
2015-01-04 17:58:56 +02:00
|
|
|
}
|
2014-09-12 13:10:30 +03:00
|
|
|
}
|
2014-12-30 22:36:03 +02:00
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
fn visit_trait_item(&mut self, t: &'v hir::TraitItem) {
|
2015-03-15 19:35:25 -06:00
|
|
|
match t.node {
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ConstTraitItem(_, ref default) => {
|
2015-03-15 19:35:25 -06:00
|
|
|
if let Some(ref expr) = *default {
|
2016-02-09 21:30:52 +01:00
|
|
|
self.global_expr(Mode::Const, &expr);
|
2015-03-15 19:35:25 -06:00
|
|
|
} else {
|
2015-11-17 17:51:44 -05:00
|
|
|
intravisit::walk_trait_item(self, t);
|
2015-03-15 19:35:25 -06:00
|
|
|
}
|
|
|
|
}
|
2015-11-17 17:51:44 -05:00
|
|
|
_ => self.with_mode(Mode::Var, |v| intravisit::walk_trait_item(v, t)),
|
2015-03-15 19:35:25 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
fn visit_impl_item(&mut self, i: &'v hir::ImplItem) {
|
2015-03-15 19:35:25 -06:00
|
|
|
match i.node {
|
2015-11-12 15:57:51 +01:00
|
|
|
hir::ImplItemKind::Const(_, ref expr) => {
|
2016-02-09 21:30:52 +01:00
|
|
|
self.global_expr(Mode::Const, &expr);
|
2015-03-15 19:35:25 -06:00
|
|
|
}
|
2015-11-17 17:51:44 -05:00
|
|
|
_ => self.with_mode(Mode::Var, |v| intravisit::walk_impl_item(v, i)),
|
2015-03-15 19:35:25 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-29 13:57:06 +02:00
|
|
|
fn visit_fn(&mut self,
|
2015-08-26 12:00:14 +02:00
|
|
|
fk: FnKind<'v>,
|
2015-07-31 00:04:06 -07:00
|
|
|
fd: &'v hir::FnDecl,
|
|
|
|
b: &'v hir::Block,
|
2015-01-29 13:57:06 +02:00
|
|
|
s: Span,
|
|
|
|
fn_id: ast::NodeId) {
|
2015-02-25 22:06:08 +02:00
|
|
|
self.fn_like(fk, fd, b, s, fn_id);
|
2015-01-29 13:57:06 +02:00
|
|
|
}
|
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
fn visit_pat(&mut self, p: &hir::Pat) {
|
2015-01-29 13:57:06 +02:00
|
|
|
match p.node {
|
2016-02-14 15:25:12 +03:00
|
|
|
PatKind::Lit(ref lit) => {
|
2016-02-09 21:30:52 +01:00
|
|
|
self.global_expr(Mode::Const, &lit);
|
2015-01-29 13:57:06 +02:00
|
|
|
}
|
2016-02-14 15:25:12 +03:00
|
|
|
PatKind::Range(ref start, ref end) => {
|
2016-02-09 21:30:52 +01:00
|
|
|
self.global_expr(Mode::Const, &start);
|
|
|
|
self.global_expr(Mode::Const, &end);
|
2015-06-30 08:53:50 -07:00
|
|
|
|
2016-07-20 00:02:56 +03:00
|
|
|
match compare_lit_exprs(self.tcx, p.span, start, end) {
|
|
|
|
Ok(Ordering::Less) |
|
|
|
|
Ok(Ordering::Equal) => {}
|
|
|
|
Ok(Ordering::Greater) => {
|
2016-08-15 00:21:13 -06:00
|
|
|
struct_span_err!(self.tcx.sess, start.span, E0030,
|
|
|
|
"lower range bound must be less than or equal to upper")
|
|
|
|
.span_label(start.span, &format!("lower bound larger than upper bound"))
|
|
|
|
.emit();
|
2015-06-30 08:53:50 -07:00
|
|
|
}
|
2016-07-20 00:02:56 +03:00
|
|
|
Err(ErrorReported) => {}
|
2015-06-30 08:53:50 -07:00
|
|
|
}
|
2015-01-29 13:57:06 +02:00
|
|
|
}
|
2016-07-21 07:01:14 +05:30
|
|
|
_ => intravisit::walk_pat(self, p),
|
2015-01-29 13:57:06 +02:00
|
|
|
}
|
2014-09-12 13:10:30 +03:00
|
|
|
}
|
2014-12-30 22:36:03 +02:00
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
fn visit_block(&mut self, block: &hir::Block) {
|
2015-02-25 22:06:08 +02:00
|
|
|
// Check all statements in the block
|
|
|
|
for stmt in &block.stmts {
|
2016-01-15 13:16:54 +01:00
|
|
|
match stmt.node {
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::StmtDecl(ref decl, _) => {
|
2015-02-25 22:06:08 +02:00
|
|
|
match decl.node {
|
2016-07-21 07:01:14 +05:30
|
|
|
hir::DeclLocal(_) => {}
|
2015-02-25 22:06:08 +02:00
|
|
|
// Item statements are allowed
|
2016-07-21 07:01:14 +05:30
|
|
|
hir::DeclItem(_) => continue,
|
2015-02-25 22:06:08 +02:00
|
|
|
}
|
|
|
|
}
|
2016-08-26 19:23:42 +03:00
|
|
|
hir::StmtExpr(..) => {}
|
|
|
|
hir::StmtSemi(..) => {}
|
2015-02-25 22:06:08 +02:00
|
|
|
}
|
2016-01-15 13:16:54 +01:00
|
|
|
self.add_qualif(ConstQualif::NOT_CONST);
|
2015-02-25 22:06:08 +02:00
|
|
|
}
|
2015-11-17 17:51:44 -05:00
|
|
|
intravisit::walk_block(self, block);
|
2015-02-25 22:06:08 +02:00
|
|
|
}
|
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
fn visit_expr(&mut self, ex: &hir::Expr) {
|
2015-01-29 13:57:06 +02:00
|
|
|
let mut outer = self.qualif;
|
2015-04-29 14:58:43 -07:00
|
|
|
self.qualif = ConstQualif::empty();
|
2015-01-29 13:57:06 +02:00
|
|
|
|
2016-10-27 04:52:10 +03:00
|
|
|
let node_ty = self.tcx.tables().node_id_to_type(ex.id);
|
2015-01-29 13:57:06 +02:00
|
|
|
check_expr(self, ex, node_ty);
|
2015-07-07 18:45:52 +03:00
|
|
|
check_adjustments(self, ex);
|
2015-01-29 13:57:06 +02:00
|
|
|
|
|
|
|
// Special-case some expressions to avoid certain flags bubbling up.
|
|
|
|
match ex.node {
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ExprCall(ref callee, ref args) => {
|
2015-06-10 17:22:20 +01:00
|
|
|
for arg in args {
|
2016-02-09 21:30:52 +01:00
|
|
|
self.visit_expr(&arg)
|
2015-01-29 13:57:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
let inner = self.qualif;
|
2016-02-09 21:30:52 +01:00
|
|
|
self.visit_expr(&callee);
|
2015-01-29 13:57:06 +02:00
|
|
|
// The callee's size doesn't count in the call.
|
|
|
|
let added = self.qualif - inner;
|
2015-04-28 16:36:22 -07:00
|
|
|
self.qualif = inner | (added - ConstQualif::NON_ZERO_SIZED);
|
2015-01-29 13:57:06 +02:00
|
|
|
}
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ExprRepeat(ref element, _) => {
|
2016-02-09 21:30:52 +01:00
|
|
|
self.visit_expr(&element);
|
2015-01-29 13:57:06 +02:00
|
|
|
// The count is checked elsewhere (typeck).
|
|
|
|
let count = match node_ty.sty {
|
2015-06-12 16:50:13 -07:00
|
|
|
ty::TyArray(_, n) => n,
|
2016-07-21 07:01:14 +05:30
|
|
|
_ => bug!(),
|
2015-01-29 13:57:06 +02:00
|
|
|
};
|
|
|
|
// [element; 0] is always zero-sized.
|
|
|
|
if count == 0 {
|
2015-04-28 16:36:22 -07:00
|
|
|
self.qualif.remove(ConstQualif::NON_ZERO_SIZED | ConstQualif::PREFER_IN_PLACE);
|
2015-01-29 13:57:06 +02:00
|
|
|
}
|
|
|
|
}
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ExprMatch(ref discr, ref arms, _) => {
|
2015-01-29 13:57:06 +02:00
|
|
|
// Compute the most demanding borrow from all the arms'
|
|
|
|
// patterns and set that on the discriminator.
|
|
|
|
let mut borrow = None;
|
2015-06-10 17:22:20 +01:00
|
|
|
for pat in arms.iter().flat_map(|arm| &arm.pats) {
|
2015-01-29 13:57:06 +02:00
|
|
|
let pat_borrow = self.rvalue_borrows.remove(&pat.id);
|
|
|
|
match (borrow, pat_borrow) {
|
2016-07-21 07:01:14 +05:30
|
|
|
(None, _) |
|
|
|
|
(_, Some(hir::MutMutable)) => {
|
2015-01-29 13:57:06 +02:00
|
|
|
borrow = pat_borrow;
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if let Some(mutbl) = borrow {
|
|
|
|
self.record_borrow(discr.id, mutbl);
|
|
|
|
}
|
2015-11-17 17:51:44 -05:00
|
|
|
intravisit::walk_expr(self, ex);
|
2015-01-29 13:57:06 +02:00
|
|
|
}
|
2016-07-21 07:01:14 +05:30
|
|
|
_ => intravisit::walk_expr(self, ex),
|
2015-01-29 13:57:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Handle borrows on (or inside the autorefs of) this expression.
|
|
|
|
match self.rvalue_borrows.remove(&ex.id) {
|
2015-07-31 00:04:06 -07:00
|
|
|
Some(hir::MutImmutable) => {
|
2015-01-29 13:57:06 +02:00
|
|
|
// Constants cannot be borrowed if they contain interior mutability as
|
|
|
|
// it means that our "silent insertion of statics" could change
|
|
|
|
// initializer values (very bad).
|
2015-04-28 16:36:22 -07:00
|
|
|
// If the type doesn't have interior mutability, then `ConstQualif::MUTABLE_MEM` has
|
2015-01-29 13:57:06 +02:00
|
|
|
// propagated from another error, so erroring again would be just noise.
|
2015-06-25 23:42:17 +03:00
|
|
|
let tc = node_ty.type_contents(self.tcx);
|
2015-04-28 16:36:22 -07:00
|
|
|
if self.qualif.intersects(ConstQualif::MUTABLE_MEM) && tc.interior_unsafe() {
|
|
|
|
outer = outer | ConstQualif::NOT_CONST;
|
2015-01-29 13:57:06 +02:00
|
|
|
}
|
|
|
|
// If the reference has to be 'static, avoid in-place initialization
|
|
|
|
// as that will end up pointing to the stack instead.
|
2015-04-28 16:36:22 -07:00
|
|
|
if !self.qualif.intersects(ConstQualif::NON_STATIC_BORROWS) {
|
|
|
|
self.qualif = self.qualif - ConstQualif::PREFER_IN_PLACE;
|
|
|
|
self.add_qualif(ConstQualif::HAS_STATIC_BORROWS);
|
2015-01-29 13:57:06 +02:00
|
|
|
}
|
|
|
|
}
|
2015-07-31 00:04:06 -07:00
|
|
|
Some(hir::MutMutable) => {
|
2015-01-29 13:57:06 +02:00
|
|
|
// `&mut expr` means expr could be mutated, unless it's zero-sized.
|
2015-04-28 16:36:22 -07:00
|
|
|
if self.qualif.intersects(ConstQualif::NON_ZERO_SIZED) {
|
2015-01-29 13:57:06 +02:00
|
|
|
if self.mode == Mode::Var {
|
2015-04-28 16:36:22 -07:00
|
|
|
outer = outer | ConstQualif::NOT_CONST;
|
|
|
|
self.add_qualif(ConstQualif::MUTABLE_MEM);
|
2015-01-29 13:57:06 +02:00
|
|
|
}
|
|
|
|
}
|
2015-04-28 16:36:22 -07:00
|
|
|
if !self.qualif.intersects(ConstQualif::NON_STATIC_BORROWS) {
|
|
|
|
self.add_qualif(ConstQualif::HAS_STATIC_BORROWS);
|
2015-01-29 13:57:06 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
None => {}
|
2014-10-06 21:32:58 -07:00
|
|
|
}
|
2016-04-26 11:18:48 +02:00
|
|
|
|
|
|
|
if self.mode == Mode::Var && !self.qualif.intersects(ConstQualif::NOT_CONST) {
|
|
|
|
match eval_const_expr_partial(self.tcx, ex, ExprTypeChecked, None) {
|
|
|
|
Ok(_) => {}
|
2016-07-21 07:01:14 +05:30
|
|
|
Err(ConstEvalErr { kind: UnimplementedConstVal(_), .. }) |
|
|
|
|
Err(ConstEvalErr { kind: MiscCatchAll, .. }) |
|
|
|
|
Err(ConstEvalErr { kind: MiscBinaryOp, .. }) |
|
|
|
|
Err(ConstEvalErr { kind: NonConstPath, .. }) |
|
|
|
|
Err(ConstEvalErr { kind: UnresolvedPath, .. }) |
|
|
|
|
Err(ConstEvalErr { kind: ErroneousReferencedConstant(_), .. }) |
|
|
|
|
Err(ConstEvalErr { kind: Math(ConstMathErr::Overflow(Op::Shr)), .. }) |
|
|
|
|
Err(ConstEvalErr { kind: Math(ConstMathErr::Overflow(Op::Shl)), .. }) |
|
|
|
|
Err(ConstEvalErr { kind: IndexOpFeatureGated, .. }) => {}
|
2016-04-26 11:18:48 +02:00
|
|
|
Err(msg) => {
|
2016-07-21 07:01:14 +05:30
|
|
|
self.tcx.sess.add_lint(CONST_ERR,
|
|
|
|
ex.id,
|
2016-04-26 11:18:48 +02:00
|
|
|
msg.span,
|
2016-07-20 00:02:56 +03:00
|
|
|
msg.description().into_oneline().into_owned())
|
2016-04-26 11:18:48 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-29 13:57:06 +02:00
|
|
|
self.tcx.const_qualif_map.borrow_mut().insert(ex.id, self.qualif);
|
|
|
|
// Don't propagate certain flags.
|
2015-04-28 16:36:22 -07:00
|
|
|
self.qualif = outer | (self.qualif - ConstQualif::HAS_STATIC_BORROWS);
|
2013-08-13 02:10:10 +02:00
|
|
|
}
|
|
|
|
}
|
2011-11-08 18:26:02 -08:00
|
|
|
|
2014-12-30 22:36:03 +02:00
|
|
|
/// 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
|
2015-01-29 13:57:06 +02:00
|
|
|
/// of a const/static item, it is qualified for promotion
|
|
|
|
/// instead of producing errors.
|
2016-07-21 07:01:14 +05:30
|
|
|
fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node_ty: Ty<'tcx>) {
|
2014-12-30 22:36:03 +02:00
|
|
|
match node_ty.sty {
|
2016-09-06 01:26:02 +03:00
|
|
|
ty::TyAdt(def, _) if def.has_dtor() => {
|
2015-04-28 16:36:22 -07:00
|
|
|
v.add_qualif(ConstQualif::NEEDS_DROP);
|
2014-12-30 22:36:03 +02:00
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
|
2015-01-29 13:57:06 +02:00
|
|
|
let method_call = ty::MethodCall::expr(e.id);
|
2014-10-06 21:32:58 -07:00
|
|
|
match e.node {
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ExprUnary(..) |
|
|
|
|
hir::ExprBinary(..) |
|
2016-10-27 04:52:10 +03:00
|
|
|
hir::ExprIndex(..) if v.tcx.tables().method_map.contains_key(&method_call) => {
|
2015-04-28 16:36:22 -07:00
|
|
|
v.add_qualif(ConstQualif::NOT_CONST);
|
2015-01-29 13:57:06 +02:00
|
|
|
}
|
2015-09-24 18:00:08 +03:00
|
|
|
hir::ExprBox(_) => {
|
2015-04-28 16:36:22 -07:00
|
|
|
v.add_qualif(ConstQualif::NOT_CONST);
|
2014-10-06 21:32:58 -07:00
|
|
|
}
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ExprUnary(op, ref inner) => {
|
2016-10-27 04:52:10 +03:00
|
|
|
match v.tcx.tables().node_id_to_type(inner.id).sty {
|
2015-06-11 16:21:46 -07:00
|
|
|
ty::TyRawPtr(_) => {
|
2015-07-31 00:04:06 -07:00
|
|
|
assert!(op == hir::UnDeref);
|
2015-05-28 00:35:56 +03:00
|
|
|
|
|
|
|
v.add_qualif(ConstQualif::NOT_CONST);
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ExprBinary(op, ref lhs, _) => {
|
2016-10-27 04:52:10 +03:00
|
|
|
match v.tcx.tables().node_id_to_type(lhs.id).sty {
|
2015-06-11 16:21:46 -07:00
|
|
|
ty::TyRawPtr(_) => {
|
2015-07-31 00:04:06 -07:00
|
|
|
assert!(op.node == hir::BiEq || op.node == hir::BiNe ||
|
|
|
|
op.node == hir::BiLe || op.node == hir::BiLt ||
|
|
|
|
op.node == hir::BiGe || op.node == hir::BiGt);
|
2015-05-28 00:35:56 +03:00
|
|
|
|
2015-04-28 16:36:22 -07:00
|
|
|
v.add_qualif(ConstQualif::NOT_CONST);
|
2015-01-29 13:57:06 +02:00
|
|
|
}
|
|
|
|
_ => {}
|
2012-01-26 12:26:14 +01:00
|
|
|
}
|
2014-10-06 21:32:58 -07:00
|
|
|
}
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ExprCast(ref from, _) => {
|
2015-05-05 19:36:47 +03:00
|
|
|
debug!("Checking const cast(id={})", from.id);
|
|
|
|
match v.tcx.cast_kinds.borrow().get(&from.id) {
|
2016-03-28 23:03:47 +02:00
|
|
|
None => span_bug!(e.span, "no kind for cast"),
|
2015-05-14 15:04:49 +03:00
|
|
|
Some(&CastKind::PtrAddrCast) | Some(&CastKind::FnPtrAddrCast) => {
|
2015-05-05 19:36:47 +03:00
|
|
|
v.add_qualif(ConstQualif::NOT_CONST);
|
2015-01-29 13:57:06 +02:00
|
|
|
}
|
2015-05-05 19:36:47 +03:00
|
|
|
_ => {}
|
2012-03-14 18:04:03 +01:00
|
|
|
}
|
2014-10-06 21:32:58 -07:00
|
|
|
}
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ExprPath(..) => {
|
2016-06-03 23:15:00 +03:00
|
|
|
match v.tcx.expect_def(e.id) {
|
2016-09-15 00:51:46 +03:00
|
|
|
Def::VariantCtor(_, CtorKind::Const) => {
|
|
|
|
// Size is determined by the whole enum, may be non-zero.
|
2015-04-28 16:36:22 -07:00
|
|
|
v.add_qualif(ConstQualif::NON_ZERO_SIZED);
|
2015-01-29 13:57:06 +02:00
|
|
|
}
|
2016-09-15 00:51:46 +03:00
|
|
|
Def::VariantCtor(..) | Def::StructCtor(..) |
|
|
|
|
Def::Fn(..) | Def::Method(..) => {}
|
2016-06-03 23:15:00 +03:00
|
|
|
Def::Static(..) => {
|
2015-01-29 13:57:06 +02:00
|
|
|
match v.mode {
|
|
|
|
Mode::Static | Mode::StaticMut => {}
|
2016-05-07 19:14:28 +03:00
|
|
|
Mode::Const | Mode::ConstFn => {}
|
2015-04-28 16:36:22 -07:00
|
|
|
Mode::Var => v.add_qualif(ConstQualif::NOT_CONST)
|
2015-01-29 13:57:06 +02:00
|
|
|
}
|
|
|
|
}
|
2016-06-03 23:15:00 +03:00
|
|
|
Def::Const(did) | Def::AssociatedConst(did) => {
|
2016-10-27 04:52:10 +03:00
|
|
|
let substs = Some(v.tcx.tables().node_id_item_substs(e.id)
|
|
|
|
.unwrap_or_else(|| v.tcx.intern_substs(&[])));
|
2016-03-30 13:43:36 +02:00
|
|
|
if let Some((expr, _)) = lookup_const_by_id(v.tcx, did, substs) {
|
2015-01-29 13:57:06 +02:00
|
|
|
let inner = v.global_expr(Mode::Const, expr);
|
|
|
|
v.add_qualif(inner);
|
|
|
|
}
|
2014-12-30 22:36:03 +02:00
|
|
|
}
|
2016-06-03 23:15:00 +03:00
|
|
|
Def::Local(..) if v.mode == Mode::ConstFn => {
|
2015-02-25 22:06:08 +02:00
|
|
|
// Sadly, we can't determine whether the types are zero-sized.
|
2015-05-05 08:47:04 -04:00
|
|
|
v.add_qualif(ConstQualif::NOT_CONST | ConstQualif::NON_ZERO_SIZED);
|
2015-02-25 22:06:08 +02:00
|
|
|
}
|
2016-05-07 19:14:28 +03:00
|
|
|
_ => {
|
2015-04-28 16:36:22 -07:00
|
|
|
v.add_qualif(ConstQualif::NOT_CONST);
|
2014-10-06 21:32:58 -07:00
|
|
|
}
|
2012-11-30 16:29:28 -08:00
|
|
|
}
|
2014-10-06 21:32:58 -07:00
|
|
|
}
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ExprCall(ref callee, _) => {
|
2015-01-29 13:57:06 +02:00
|
|
|
let mut callee = &**callee;
|
|
|
|
loop {
|
|
|
|
callee = match callee.node {
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ExprBlock(ref block) => match block.expr {
|
2016-02-09 21:30:52 +01:00
|
|
|
Some(ref tail) => &tail,
|
2015-01-29 13:57:06 +02:00
|
|
|
None => break
|
|
|
|
},
|
|
|
|
_ => break
|
|
|
|
};
|
|
|
|
}
|
2016-06-03 23:15:00 +03:00
|
|
|
// The callee is an arbitrary expression, it doesn't necessarily have a definition.
|
|
|
|
let is_const = match v.tcx.expect_def_or_none(callee.id) {
|
2016-09-15 00:51:46 +03:00
|
|
|
Some(Def::StructCtor(_, CtorKind::Fn)) |
|
|
|
|
Some(Def::VariantCtor(_, CtorKind::Fn)) => {
|
|
|
|
// `NON_ZERO_SIZED` is about the call result, not about the ctor itself.
|
2015-04-28 16:36:22 -07:00
|
|
|
v.add_qualif(ConstQualif::NON_ZERO_SIZED);
|
2015-02-25 22:06:08 +02:00
|
|
|
true
|
2015-01-29 13:57:06 +02:00
|
|
|
}
|
2016-01-20 22:31:10 +03:00
|
|
|
Some(Def::Fn(did)) => {
|
2015-05-28 11:22:00 -04:00
|
|
|
v.handle_const_fn_call(e, did, node_ty)
|
2015-02-25 22:06:08 +02:00
|
|
|
}
|
2016-01-20 22:31:10 +03:00
|
|
|
Some(Def::Method(did)) => {
|
2015-08-04 01:16:53 +03:00
|
|
|
match v.tcx.impl_or_trait_item(did).container() {
|
|
|
|
ty::ImplContainer(_) => {
|
|
|
|
v.handle_const_fn_call(e, did, node_ty)
|
|
|
|
}
|
|
|
|
ty::TraitContainer(_) => false
|
|
|
|
}
|
|
|
|
}
|
2015-02-25 22:06:08 +02:00
|
|
|
_ => false
|
|
|
|
};
|
|
|
|
if !is_const {
|
|
|
|
v.add_qualif(ConstQualif::NOT_CONST);
|
2012-04-04 15:02:25 -07:00
|
|
|
}
|
2014-10-06 21:32:58 -07:00
|
|
|
}
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ExprMethodCall(..) => {
|
2016-10-27 04:52:10 +03:00
|
|
|
let method = v.tcx.tables().method_map[&method_call];
|
2015-07-04 07:07:10 +03:00
|
|
|
let is_const = match v.tcx.impl_or_trait_item(method.def_id).container() {
|
|
|
|
ty::ImplContainer(_) => v.handle_const_fn_call(e, method.def_id, node_ty),
|
|
|
|
ty::TraitContainer(_) => false
|
2015-02-25 22:06:08 +02:00
|
|
|
};
|
|
|
|
if !is_const {
|
2015-05-05 08:47:04 -04:00
|
|
|
v.add_qualif(ConstQualif::NOT_CONST);
|
2014-05-04 10:39:11 +02:00
|
|
|
}
|
2014-10-06 21:32:58 -07:00
|
|
|
}
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ExprStruct(..) => {
|
2016-10-27 04:52:10 +03:00
|
|
|
if let ty::TyAdt(adt, ..) = v.tcx.tables().expr_ty(e).sty {
|
2016-09-15 00:51:46 +03:00
|
|
|
// unsafe_cell_type doesn't necessarily exist with no_core
|
|
|
|
if Some(adt.did) == v.tcx.lang_items.unsafe_cell_type() {
|
|
|
|
v.add_qualif(ConstQualif::MUTABLE_MEM);
|
|
|
|
}
|
2014-12-30 22:36:03 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ExprLit(_) |
|
|
|
|
hir::ExprAddrOf(..) => {
|
2015-04-28 16:36:22 -07:00
|
|
|
v.add_qualif(ConstQualif::NON_ZERO_SIZED);
|
2015-01-29 13:57:06 +02:00
|
|
|
}
|
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ExprRepeat(..) => {
|
2015-04-28 16:36:22 -07:00
|
|
|
v.add_qualif(ConstQualif::PREFER_IN_PLACE);
|
2015-01-29 13:57:06 +02:00
|
|
|
}
|
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ExprClosure(..) => {
|
2015-02-25 22:06:08 +02:00
|
|
|
// Paths in constant contexts cannot refer to local variables,
|
2015-01-29 13:57:06 +02:00
|
|
|
// as there are none, and thus closures can't have upvars there.
|
2015-06-25 23:42:17 +03:00
|
|
|
if v.tcx.with_freevars(e.id, |fv| !fv.is_empty()) {
|
2015-01-29 13:57:06 +02:00
|
|
|
assert!(v.mode == Mode::Var,
|
|
|
|
"global closures can't capture anything");
|
2015-04-28 16:36:22 -07:00
|
|
|
v.add_qualif(ConstQualif::NOT_CONST);
|
2015-01-29 13:57:06 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ExprBlock(_) |
|
|
|
|
hir::ExprIndex(..) |
|
|
|
|
hir::ExprField(..) |
|
|
|
|
hir::ExprTupField(..) |
|
2016-09-20 02:14:46 +02:00
|
|
|
hir::ExprArray(_) |
|
2015-02-01 09:59:46 +02:00
|
|
|
hir::ExprType(..) |
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ExprTup(..) => {}
|
2014-09-13 20:10:34 +03:00
|
|
|
|
2014-12-30 22:36:03 +02:00
|
|
|
// Conditional control flow (possible to implement).
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ExprMatch(..) |
|
|
|
|
hir::ExprIf(..) |
|
2014-10-06 21:32:58 -07:00
|
|
|
|
2014-12-30 22:36:03 +02:00
|
|
|
// Loops (not very meaningful in constants).
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ExprWhile(..) |
|
|
|
|
hir::ExprLoop(..) |
|
2014-12-30 22:36:03 +02:00
|
|
|
|
|
|
|
// More control flow (also not very meaningful).
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ExprBreak(_) |
|
|
|
|
hir::ExprAgain(_) |
|
|
|
|
hir::ExprRet(_) |
|
2014-12-30 22:36:03 +02:00
|
|
|
|
2015-02-25 22:06:08 +02:00
|
|
|
// Expressions with side-effects.
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ExprAssign(..) |
|
|
|
|
hir::ExprAssignOp(..) |
|
2016-03-09 22:17:02 +02:00
|
|
|
hir::ExprInlineAsm(..) => {
|
2015-04-28 16:36:22 -07:00
|
|
|
v.add_qualif(ConstQualif::NOT_CONST);
|
2014-10-06 21:32:58 -07:00
|
|
|
}
|
2014-12-30 22:36:03 +02:00
|
|
|
}
|
|
|
|
}
|
2013-11-16 01:58:51 -05:00
|
|
|
|
2015-07-07 18:45:52 +03:00
|
|
|
/// Check the adjustments of an expression
|
2015-07-31 00:04:06 -07:00
|
|
|
fn check_adjustments<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr) {
|
2016-10-20 06:33:20 +03:00
|
|
|
use rustc::ty::adjustment::*;
|
|
|
|
|
|
|
|
match v.tcx.tables().adjustments.get(&e.id).map(|adj| adj.kind) {
|
2015-09-14 14:55:56 +03:00
|
|
|
None |
|
2016-10-20 06:33:20 +03:00
|
|
|
Some(Adjust::NeverToAny) |
|
|
|
|
Some(Adjust::ReifyFnPointer) |
|
|
|
|
Some(Adjust::UnsafeFnPointer) |
|
|
|
|
Some(Adjust::MutToConstPointer) => {}
|
2015-09-14 14:55:56 +03:00
|
|
|
|
2016-10-20 06:33:20 +03:00
|
|
|
Some(Adjust::DerefRef { autoderefs, .. }) => {
|
2016-07-21 07:01:14 +05:30
|
|
|
if (0..autoderefs as u32)
|
2016-10-27 04:52:10 +03:00
|
|
|
.any(|autoderef| v.tcx.tables().is_overloaded_autoderef(e.id, autoderef)) {
|
2015-07-07 18:45:52 +03:00
|
|
|
v.add_qualif(ConstQualif::NOT_CONST);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-03 05:23:22 +03:00
|
|
|
pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
|
2016-07-21 07:01:14 +05:30
|
|
|
tcx.visit_all_items_in_krate(DepNode::CheckConst,
|
|
|
|
&mut CheckCrateVisitor {
|
|
|
|
tcx: tcx,
|
|
|
|
mode: Mode::Var,
|
|
|
|
qualif: ConstQualif::NOT_CONST,
|
|
|
|
rvalue_borrows: NodeMap(),
|
|
|
|
});
|
2014-12-30 22:36:03 +02:00
|
|
|
tcx.sess.abort_if_errors();
|
|
|
|
}
|
|
|
|
|
2016-05-11 04:14:41 +03:00
|
|
|
impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for CheckCrateVisitor<'a, 'gcx> {
|
2014-12-30 22:36:03 +02:00
|
|
|
fn consume(&mut self,
|
|
|
|
_consume_id: ast::NodeId,
|
2016-05-07 19:14:28 +03:00
|
|
|
_consume_span: Span,
|
2014-12-30 22:36:03 +02:00
|
|
|
cmt: mc::cmt,
|
|
|
|
_mode: euv::ConsumeMode) {
|
|
|
|
let mut cur = &cmt;
|
|
|
|
loop {
|
|
|
|
match cur.cat {
|
2015-10-03 21:36:16 +02:00
|
|
|
Categorization::StaticItem => {
|
2014-12-30 22:36:03 +02:00
|
|
|
break;
|
|
|
|
}
|
2016-08-26 19:23:42 +03:00
|
|
|
Categorization::Deref(ref cmt, ..) |
|
2015-10-03 21:36:16 +02:00
|
|
|
Categorization::Downcast(ref cmt, _) |
|
|
|
|
Categorization::Interior(ref cmt, _) => cur = cmt,
|
2014-12-30 22:36:03 +02:00
|
|
|
|
2015-10-03 21:36:16 +02:00
|
|
|
Categorization::Rvalue(..) |
|
|
|
|
Categorization::Upvar(..) |
|
2016-07-21 07:01:14 +05:30
|
|
|
Categorization::Local(..) => break,
|
2014-12-30 22:36:03 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fn borrow(&mut self,
|
2015-01-29 13:57:06 +02:00
|
|
|
borrow_id: ast::NodeId,
|
2016-05-07 19:14:28 +03:00
|
|
|
_borrow_span: Span,
|
2014-12-30 22:36:03 +02:00
|
|
|
cmt: mc::cmt<'tcx>,
|
2016-08-25 23:58:52 +03:00
|
|
|
_loan_region: &'tcx ty::Region,
|
2015-01-29 13:57:06 +02:00
|
|
|
bk: ty::BorrowKind,
|
2016-07-21 07:01:14 +05:30
|
|
|
loan_cause: euv::LoanCause) {
|
2015-04-08 04:31:51 -04:00
|
|
|
// Kind of hacky, but we allow Unsafe coercions in constants.
|
|
|
|
// These occur when we convert a &T or *T to a *U, as well as
|
|
|
|
// when making a thin pointer (e.g., `*T`) into a fat pointer
|
|
|
|
// (e.g., `*Trait`).
|
|
|
|
match loan_cause {
|
|
|
|
euv::LoanCause::AutoUnsafe => {
|
|
|
|
return;
|
|
|
|
}
|
2016-07-21 07:01:14 +05:30
|
|
|
_ => {}
|
2015-04-08 04:31:51 -04:00
|
|
|
}
|
|
|
|
|
2014-12-30 22:36:03 +02:00
|
|
|
let mut cur = &cmt;
|
|
|
|
loop {
|
|
|
|
match cur.cat {
|
2015-10-03 21:36:16 +02:00
|
|
|
Categorization::Rvalue(..) => {
|
2015-01-29 13:57:06 +02:00
|
|
|
if loan_cause == euv::MatchDiscriminant {
|
|
|
|
// Ignore the dummy immutable borrow created by EUV.
|
|
|
|
break;
|
2014-12-30 22:36:03 +02:00
|
|
|
}
|
2015-01-29 13:57:06 +02:00
|
|
|
let mutbl = bk.to_mutbl_lossy();
|
2015-07-31 00:04:06 -07:00
|
|
|
if mutbl == hir::MutMutable && self.mode == Mode::StaticMut {
|
2015-06-12 16:50:13 -07:00
|
|
|
// Mutable slices are the only `&mut` allowed in
|
|
|
|
// globals, but only in `static mut`, nowhere else.
|
|
|
|
// FIXME: This exception is really weird... there isn't
|
|
|
|
// any fundamental reason to restrict this based on
|
|
|
|
// type of the expression. `&mut [1]` has exactly the
|
|
|
|
// same representation as &mut 1.
|
2015-01-29 13:57:06 +02:00
|
|
|
match cmt.ty.sty {
|
2016-08-26 19:23:42 +03:00
|
|
|
ty::TyArray(..) |
|
2016-07-21 07:01:14 +05:30
|
|
|
ty::TySlice(_) => break,
|
2015-01-29 13:57:06 +02:00
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
self.record_borrow(borrow_id, mutbl);
|
2014-12-30 22:36:03 +02:00
|
|
|
break;
|
|
|
|
}
|
2015-10-03 21:36:16 +02:00
|
|
|
Categorization::StaticItem => {
|
2014-12-30 22:36:03 +02:00
|
|
|
break;
|
|
|
|
}
|
2016-08-26 19:23:42 +03:00
|
|
|
Categorization::Deref(ref cmt, ..) |
|
2015-10-03 21:36:16 +02:00
|
|
|
Categorization::Downcast(ref cmt, _) |
|
|
|
|
Categorization::Interior(ref cmt, _) => {
|
2014-12-30 22:36:03 +02:00
|
|
|
cur = cmt;
|
|
|
|
}
|
|
|
|
|
2015-10-03 21:36:16 +02:00
|
|
|
Categorization::Upvar(..) |
|
2016-07-21 07:01:14 +05:30
|
|
|
Categorization::Local(..) => break,
|
2014-12-30 22:36:03 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-21 07:01:14 +05:30
|
|
|
fn decl_without_init(&mut self, _id: ast::NodeId, _span: Span) {}
|
2014-12-30 22:36:03 +02:00
|
|
|
fn mutate(&mut self,
|
|
|
|
_assignment_id: ast::NodeId,
|
|
|
|
_assignment_span: Span,
|
|
|
|
_assignee_cmt: mc::cmt,
|
2016-07-21 07:01:14 +05:30
|
|
|
_mode: euv::MutateMode) {
|
|
|
|
}
|
2014-12-30 22:36:03 +02:00
|
|
|
|
2016-07-21 07:01:14 +05:30
|
|
|
fn matched_pat(&mut self, _: &hir::Pat, _: mc::cmt, _: euv::MatchMode) {}
|
2014-12-30 22:36:03 +02:00
|
|
|
|
2016-07-21 07:01:14 +05:30
|
|
|
fn consume_pat(&mut self, _consume_pat: &hir::Pat, _cmt: mc::cmt, _mode: euv::ConsumeMode) {}
|
2015-01-29 13:57:06 +02:00
|
|
|
}
|