]> git.proxmox.com Git - rustc.git/blame - src/librustc_passes/consts.rs
New upstream version 1.13.0+dfsg1
[rustc.git] / src / librustc_passes / consts.rs
CommitLineData
85aaf69f 1// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
223e47cc
LB
2// file at the top-level directory of this distribution and at
3// http://rust-lang.org/COPYRIGHT.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
85aaf69f
SL
11// Verifies that the types and values of const and static items
12// are safe. The rules enforced by this module are:
13//
14// - For each *mutable* static item, it checks that its **type**:
15// - doesn't have a destructor
62682a34 16// - doesn't own a box
85aaf69f
SL
17//
18// - For each *immutable* static item, it checks that its **value**:
62682a34 19// - doesn't own a box
85aaf69f
SL
20// - doesn't contain a struct literal or a call to an enum variant / struct constructor where
21// - the type of the struct/enum has a dtor
22//
23// Rules Enforced Elsewhere:
24// - It's not possible to take the address of a static item with unsafe interior. This is enforced
25// by borrowck::gather_loans
223e47cc 26
7453a54e 27use rustc::dep_graph::DepNode;
5bcae85e 28use rustc::ty::cast::CastKind;
54a0048b
SL
29use rustc_const_eval::{ConstEvalErr, lookup_const_fn_by_id, compare_lit_exprs};
30use rustc_const_eval::{eval_const_expr_partial, lookup_const_by_id};
a7813a04
XL
31use rustc_const_eval::ErrKind::{IndexOpFeatureGated, UnimplementedConstVal, MiscCatchAll, Math};
32use rustc_const_eval::ErrKind::{ErroneousReferencedConstant, MiscBinaryOp, NonConstPath};
33use rustc_const_eval::ErrKind::UnresolvedPath;
54a0048b 34use rustc_const_eval::EvalHint::ExprTypeChecked;
a7813a04 35use rustc_const_math::{ConstMathErr, Op};
54a0048b
SL
36use rustc::hir::def::Def;
37use rustc::hir::def_id::DefId;
7453a54e 38use rustc::middle::expr_use_visitor as euv;
7453a54e
SL
39use rustc::middle::mem_categorization as mc;
40use rustc::middle::mem_categorization::Categorization;
54a0048b 41use rustc::ty::{self, Ty, TyCtxt};
5bcae85e
SL
42use rustc::traits::Reveal;
43use rustc::util::common::ErrorReported;
7453a54e
SL
44use rustc::util::nodemap::NodeMap;
45use rustc::middle::const_qualif::ConstQualif;
46use rustc::lint::builtin::CONST_ERR;
47
54a0048b 48use rustc::hir::{self, PatKind};
1a4d82fc 49use syntax::ast;
3157f602 50use syntax_pos::Span;
54a0048b 51use rustc::hir::intravisit::{self, FnKind, Visitor};
223e47cc 52
85aaf69f 53use std::collections::hash_map::Entry;
c1a9b12d 54use std::cmp::Ordering;
85aaf69f 55
92a42be0 56#[derive(Copy, Clone, Debug, Eq, PartialEq)]
85aaf69f
SL
57enum Mode {
58 Const,
62682a34 59 ConstFn,
85aaf69f
SL
60 Static,
61 StaticMut,
62
63 // An expression that occurs outside of any constant context
64 // (i.e. `const`, `static`, array lengths, etc.). The value
65 // can be variable at runtime, but will be promotable to
66 // static memory if we can prove it is actually constant.
67 Var,
68}
69
1a4d82fc 70struct CheckCrateVisitor<'a, 'tcx: 'a> {
a7813a04 71 tcx: TyCtxt<'a, 'tcx, 'tcx>,
85aaf69f
SL
72 mode: Mode,
73 qualif: ConstQualif,
5bcae85e 74 rvalue_borrows: NodeMap<hir::Mutability>,
223e47cc
LB
75}
76
a7813a04 77impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
5bcae85e
SL
78 fn with_mode<F, R>(&mut self, mode: Mode, f: F) -> R
79 where F: FnOnce(&mut CheckCrateVisitor<'a, 'gcx>) -> R
1a4d82fc 80 {
85aaf69f
SL
81 let (old_mode, old_qualif) = (self.mode, self.qualif);
82 self.mode = mode;
d9579d0f 83 self.qualif = ConstQualif::empty();
85aaf69f
SL
84 let r = f(self);
85 self.mode = old_mode;
86 self.qualif = old_qualif;
87 r
1a4d82fc 88 }
85aaf69f 89
5bcae85e
SL
90 fn with_euv<F, R>(&mut self, item_id: Option<ast::NodeId>, f: F) -> R
91 where F: for<'b, 'tcx> FnOnce(&mut euv::ExprUseVisitor<'b, 'gcx, 'tcx>) -> R
1a4d82fc 92 {
85aaf69f
SL
93 let param_env = match item_id {
94 Some(item_id) => ty::ParameterEnvironment::for_item(self.tcx, item_id),
5bcae85e 95 None => self.tcx.empty_parameter_environment(),
85aaf69f 96 };
c1a9b12d 97
5bcae85e
SL
98 self.tcx
99 .infer_ctxt(None, Some(param_env), Reveal::NotSpecializable)
100 .enter(|infcx| f(&mut euv::ExprUseVisitor::new(self, &infcx)))
85aaf69f
SL
101 }
102
e9174d1e 103 fn global_expr(&mut self, mode: Mode, expr: &hir::Expr) -> ConstQualif {
85aaf69f
SL
104 assert!(mode != Mode::Var);
105 match self.tcx.const_qualif_map.borrow_mut().entry(expr.id) {
106 Entry::Occupied(entry) => return *entry.get(),
107 Entry::Vacant(entry) => {
108 // Prevent infinite recursion on re-entry.
d9579d0f 109 entry.insert(ConstQualif::empty());
85aaf69f
SL
110 }
111 }
54a0048b
SL
112 if let Err(err) = eval_const_expr_partial(self.tcx, expr, ExprTypeChecked, None) {
113 match err.kind {
5bcae85e
SL
114 UnimplementedConstVal(_) => {}
115 IndexOpFeatureGated => {}
116 ErroneousReferencedConstant(_) => {}
117 _ => {
118 self.tcx.sess.add_lint(CONST_ERR,
119 expr.id,
120 expr.span,
121 format!("constant evaluation error: {}. This will \
122 become a HARD ERROR in the future",
123 err.description().into_oneline()))
124 }
54a0048b
SL
125 }
126 }
85aaf69f
SL
127 self.with_mode(mode, |this| {
128 this.with_euv(None, |euv| euv.consume_expr(expr));
129 this.visit_expr(expr);
130 this.qualif
131 })
132 }
133
62682a34 134 fn fn_like(&mut self,
e9174d1e
SL
135 fk: FnKind,
136 fd: &hir::FnDecl,
137 b: &hir::Block,
62682a34
SL
138 s: Span,
139 fn_id: ast::NodeId)
140 -> ConstQualif {
141 match self.tcx.const_qualif_map.borrow_mut().entry(fn_id) {
142 Entry::Occupied(entry) => return *entry.get(),
143 Entry::Vacant(entry) => {
144 // Prevent infinite recursion on re-entry.
145 entry.insert(ConstQualif::empty());
146 }
147 }
148
149 let mode = match fk {
9e0c209e
SL
150 FnKind::ItemFn(_, _, _, hir::Constness::Const, ..)
151 => Mode::ConstFn,
152 FnKind::Method(_, m, ..) => {
e9174d1e 153 if m.constness == hir::Constness::Const {
62682a34
SL
154 Mode::ConstFn
155 } else {
156 Mode::Var
157 }
158 }
5bcae85e 159 _ => Mode::Var,
62682a34
SL
160 };
161
62682a34
SL
162 let qualif = self.with_mode(mode, |this| {
163 this.with_euv(Some(fn_id), |euv| euv.walk_fn(fd, b));
5bcae85e 164 intravisit::walk_fn(this, fk, fd, b, s, fn_id);
62682a34
SL
165 this.qualif
166 });
167
168 // Keep only bits that aren't affected by function body (NON_ZERO_SIZED),
169 // and bits that don't change semantics, just optimizations (PREFER_IN_PLACE).
170 let qualif = qualif & (ConstQualif::NON_ZERO_SIZED | ConstQualif::PREFER_IN_PLACE);
171
172 self.tcx.const_qualif_map.borrow_mut().insert(fn_id, qualif);
173 qualif
174 }
175
85aaf69f
SL
176 fn add_qualif(&mut self, qualif: ConstQualif) {
177 self.qualif = self.qualif | qualif;
178 }
179
62682a34 180 /// Returns true if the call is to a const fn or method.
5bcae85e 181 fn handle_const_fn_call(&mut self, _expr: &hir::Expr, def_id: DefId, ret_ty: Ty<'gcx>) -> bool {
54a0048b 182 if let Some(fn_like) = lookup_const_fn_by_id(self.tcx, def_id) {
62682a34
SL
183 let qualif = self.fn_like(fn_like.kind(),
184 fn_like.decl(),
185 fn_like.body(),
186 fn_like.span(),
187 fn_like.id());
188 self.add_qualif(qualif);
189
c1a9b12d 190 if ret_ty.type_contents(self.tcx).interior_unsafe() {
62682a34
SL
191 self.add_qualif(ConstQualif::MUTABLE_MEM);
192 }
193
194 true
195 } else {
196 false
197 }
198 }
199
e9174d1e 200 fn record_borrow(&mut self, id: ast::NodeId, mutbl: hir::Mutability) {
85aaf69f
SL
201 match self.rvalue_borrows.entry(id) {
202 Entry::Occupied(mut entry) => {
203 // Merge the two borrows, taking the most demanding
204 // one, mutability-wise.
e9174d1e 205 if mutbl == hir::MutMutable {
85aaf69f
SL
206 entry.insert(mutbl);
207 }
208 }
209 Entry::Vacant(entry) => {
210 entry.insert(mutbl);
211 }
212 }
213 }
223e47cc
LB
214}
215
1a4d82fc 216impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
e9174d1e 217 fn visit_item(&mut self, i: &hir::Item) {
62682a34 218 debug!("visit_item(item={})", self.tcx.map.node_to_string(i.id));
92a42be0 219 assert_eq!(self.mode, Mode::Var);
1a4d82fc 220 match i.node {
e9174d1e 221 hir::ItemStatic(_, hir::MutImmutable, ref expr) => {
7453a54e 222 self.global_expr(Mode::Static, &expr);
85aaf69f 223 }
e9174d1e 224 hir::ItemStatic(_, hir::MutMutable, ref expr) => {
7453a54e 225 self.global_expr(Mode::StaticMut, &expr);
85aaf69f 226 }
e9174d1e 227 hir::ItemConst(_, ref expr) => {
7453a54e 228 self.global_expr(Mode::Const, &expr);
1a4d82fc 229 }
e9174d1e 230 hir::ItemEnum(ref enum_definition, _) => {
85aaf69f
SL
231 for var in &enum_definition.variants {
232 if let Some(ref ex) = var.node.disr_expr {
7453a54e 233 self.global_expr(Mode::Const, &ex);
1a4d82fc 234 }
85aaf69f
SL
235 }
236 }
237 _ => {
92a42be0 238 intravisit::walk_item(self, i);
1a4d82fc 239 }
223e47cc
LB
240 }
241 }
85aaf69f 242
e9174d1e 243 fn visit_trait_item(&mut self, t: &'v hir::TraitItem) {
d9579d0f 244 match t.node {
e9174d1e 245 hir::ConstTraitItem(_, ref default) => {
d9579d0f 246 if let Some(ref expr) = *default {
7453a54e 247 self.global_expr(Mode::Const, &expr);
d9579d0f 248 } else {
92a42be0 249 intravisit::walk_trait_item(self, t);
d9579d0f
AL
250 }
251 }
92a42be0 252 _ => self.with_mode(Mode::Var, |v| intravisit::walk_trait_item(v, t)),
d9579d0f
AL
253 }
254 }
255
e9174d1e 256 fn visit_impl_item(&mut self, i: &'v hir::ImplItem) {
d9579d0f 257 match i.node {
92a42be0 258 hir::ImplItemKind::Const(_, ref expr) => {
7453a54e 259 self.global_expr(Mode::Const, &expr);
d9579d0f 260 }
92a42be0 261 _ => self.with_mode(Mode::Var, |v| intravisit::walk_impl_item(v, i)),
d9579d0f
AL
262 }
263 }
264
85aaf69f 265 fn visit_fn(&mut self,
e9174d1e
SL
266 fk: FnKind<'v>,
267 fd: &'v hir::FnDecl,
268 b: &'v hir::Block,
85aaf69f
SL
269 s: Span,
270 fn_id: ast::NodeId) {
62682a34 271 self.fn_like(fk, fd, b, s, fn_id);
85aaf69f
SL
272 }
273
e9174d1e 274 fn visit_pat(&mut self, p: &hir::Pat) {
85aaf69f 275 match p.node {
7453a54e
SL
276 PatKind::Lit(ref lit) => {
277 self.global_expr(Mode::Const, &lit);
85aaf69f 278 }
7453a54e
SL
279 PatKind::Range(ref start, ref end) => {
280 self.global_expr(Mode::Const, &start);
281 self.global_expr(Mode::Const, &end);
c1a9b12d 282
5bcae85e
SL
283 match compare_lit_exprs(self.tcx, p.span, start, end) {
284 Ok(Ordering::Less) |
285 Ok(Ordering::Equal) => {}
286 Ok(Ordering::Greater) => {
9e0c209e
SL
287 struct_span_err!(self.tcx.sess, start.span, E0030,
288 "lower range bound must be less than or equal to upper")
289 .span_label(start.span, &format!("lower bound larger than upper bound"))
290 .emit();
c1a9b12d 291 }
5bcae85e 292 Err(ErrorReported) => {}
c1a9b12d 293 }
85aaf69f 294 }
5bcae85e 295 _ => intravisit::walk_pat(self, p),
85aaf69f 296 }
223e47cc 297 }
85aaf69f 298
e9174d1e 299 fn visit_block(&mut self, block: &hir::Block) {
62682a34
SL
300 // Check all statements in the block
301 for stmt in &block.stmts {
9cc50fc6 302 match stmt.node {
e9174d1e 303 hir::StmtDecl(ref decl, _) => {
62682a34 304 match decl.node {
5bcae85e 305 hir::DeclLocal(_) => {}
62682a34 306 // Item statements are allowed
5bcae85e 307 hir::DeclItem(_) => continue,
62682a34
SL
308 }
309 }
9e0c209e
SL
310 hir::StmtExpr(..) => {}
311 hir::StmtSemi(..) => {}
62682a34 312 }
9cc50fc6 313 self.add_qualif(ConstQualif::NOT_CONST);
62682a34 314 }
92a42be0 315 intravisit::walk_block(self, block);
62682a34
SL
316 }
317
e9174d1e 318 fn visit_expr(&mut self, ex: &hir::Expr) {
85aaf69f 319 let mut outer = self.qualif;
d9579d0f 320 self.qualif = ConstQualif::empty();
85aaf69f 321
c1a9b12d 322 let node_ty = self.tcx.node_id_to_type(ex.id);
85aaf69f 323 check_expr(self, ex, node_ty);
c1a9b12d 324 check_adjustments(self, ex);
85aaf69f
SL
325
326 // Special-case some expressions to avoid certain flags bubbling up.
327 match ex.node {
e9174d1e 328 hir::ExprCall(ref callee, ref args) => {
62682a34 329 for arg in args {
7453a54e 330 self.visit_expr(&arg)
85aaf69f
SL
331 }
332
333 let inner = self.qualif;
7453a54e 334 self.visit_expr(&callee);
85aaf69f
SL
335 // The callee's size doesn't count in the call.
336 let added = self.qualif - inner;
d9579d0f 337 self.qualif = inner | (added - ConstQualif::NON_ZERO_SIZED);
85aaf69f 338 }
e9174d1e 339 hir::ExprRepeat(ref element, _) => {
7453a54e 340 self.visit_expr(&element);
85aaf69f
SL
341 // The count is checked elsewhere (typeck).
342 let count = match node_ty.sty {
62682a34 343 ty::TyArray(_, n) => n,
5bcae85e 344 _ => bug!(),
85aaf69f
SL
345 };
346 // [element; 0] is always zero-sized.
347 if count == 0 {
d9579d0f 348 self.qualif.remove(ConstQualif::NON_ZERO_SIZED | ConstQualif::PREFER_IN_PLACE);
85aaf69f
SL
349 }
350 }
e9174d1e 351 hir::ExprMatch(ref discr, ref arms, _) => {
85aaf69f
SL
352 // Compute the most demanding borrow from all the arms'
353 // patterns and set that on the discriminator.
354 let mut borrow = None;
62682a34 355 for pat in arms.iter().flat_map(|arm| &arm.pats) {
85aaf69f
SL
356 let pat_borrow = self.rvalue_borrows.remove(&pat.id);
357 match (borrow, pat_borrow) {
5bcae85e
SL
358 (None, _) |
359 (_, Some(hir::MutMutable)) => {
85aaf69f
SL
360 borrow = pat_borrow;
361 }
362 _ => {}
363 }
364 }
365 if let Some(mutbl) = borrow {
366 self.record_borrow(discr.id, mutbl);
367 }
92a42be0 368 intravisit::walk_expr(self, ex);
85aaf69f 369 }
5bcae85e 370 _ => intravisit::walk_expr(self, ex),
85aaf69f
SL
371 }
372
373 // Handle borrows on (or inside the autorefs of) this expression.
374 match self.rvalue_borrows.remove(&ex.id) {
e9174d1e 375 Some(hir::MutImmutable) => {
85aaf69f
SL
376 // Constants cannot be borrowed if they contain interior mutability as
377 // it means that our "silent insertion of statics" could change
378 // initializer values (very bad).
d9579d0f 379 // If the type doesn't have interior mutability, then `ConstQualif::MUTABLE_MEM` has
85aaf69f 380 // propagated from another error, so erroring again would be just noise.
c1a9b12d 381 let tc = node_ty.type_contents(self.tcx);
d9579d0f
AL
382 if self.qualif.intersects(ConstQualif::MUTABLE_MEM) && tc.interior_unsafe() {
383 outer = outer | ConstQualif::NOT_CONST;
85aaf69f
SL
384 }
385 // If the reference has to be 'static, avoid in-place initialization
386 // as that will end up pointing to the stack instead.
d9579d0f
AL
387 if !self.qualif.intersects(ConstQualif::NON_STATIC_BORROWS) {
388 self.qualif = self.qualif - ConstQualif::PREFER_IN_PLACE;
389 self.add_qualif(ConstQualif::HAS_STATIC_BORROWS);
85aaf69f
SL
390 }
391 }
e9174d1e 392 Some(hir::MutMutable) => {
85aaf69f 393 // `&mut expr` means expr could be mutated, unless it's zero-sized.
d9579d0f 394 if self.qualif.intersects(ConstQualif::NON_ZERO_SIZED) {
85aaf69f 395 if self.mode == Mode::Var {
d9579d0f
AL
396 outer = outer | ConstQualif::NOT_CONST;
397 self.add_qualif(ConstQualif::MUTABLE_MEM);
85aaf69f
SL
398 }
399 }
d9579d0f
AL
400 if !self.qualif.intersects(ConstQualif::NON_STATIC_BORROWS) {
401 self.add_qualif(ConstQualif::HAS_STATIC_BORROWS);
85aaf69f
SL
402 }
403 }
404 None => {}
1a4d82fc 405 }
a7813a04
XL
406
407 if self.mode == Mode::Var && !self.qualif.intersects(ConstQualif::NOT_CONST) {
408 match eval_const_expr_partial(self.tcx, ex, ExprTypeChecked, None) {
409 Ok(_) => {}
5bcae85e
SL
410 Err(ConstEvalErr { kind: UnimplementedConstVal(_), .. }) |
411 Err(ConstEvalErr { kind: MiscCatchAll, .. }) |
412 Err(ConstEvalErr { kind: MiscBinaryOp, .. }) |
413 Err(ConstEvalErr { kind: NonConstPath, .. }) |
414 Err(ConstEvalErr { kind: UnresolvedPath, .. }) |
415 Err(ConstEvalErr { kind: ErroneousReferencedConstant(_), .. }) |
416 Err(ConstEvalErr { kind: Math(ConstMathErr::Overflow(Op::Shr)), .. }) |
417 Err(ConstEvalErr { kind: Math(ConstMathErr::Overflow(Op::Shl)), .. }) |
418 Err(ConstEvalErr { kind: IndexOpFeatureGated, .. }) => {}
a7813a04 419 Err(msg) => {
5bcae85e
SL
420 self.tcx.sess.add_lint(CONST_ERR,
421 ex.id,
a7813a04 422 msg.span,
5bcae85e 423 msg.description().into_oneline().into_owned())
a7813a04
XL
424 }
425 }
426 }
427
85aaf69f
SL
428 self.tcx.const_qualif_map.borrow_mut().insert(ex.id, self.qualif);
429 // Don't propagate certain flags.
d9579d0f 430 self.qualif = outer | (self.qualif - ConstQualif::HAS_STATIC_BORROWS);
1a4d82fc
JJ
431 }
432}
433
85aaf69f
SL
434/// This function is used to enforce the constraints on
435/// const/static items. It walks through the *value*
436/// of the item walking down the expression and evaluating
437/// every nested expression. If the expression is not part
438/// of a const/static item, it is qualified for promotion
439/// instead of producing errors.
5bcae85e 440fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node_ty: Ty<'tcx>) {
85aaf69f 441 match node_ty.sty {
9e0c209e 442 ty::TyAdt(def, _) if def.has_dtor() => {
d9579d0f 443 v.add_qualif(ConstQualif::NEEDS_DROP);
85aaf69f
SL
444 }
445 _ => {}
446 }
223e47cc 447
85aaf69f 448 let method_call = ty::MethodCall::expr(e.id);
1a4d82fc 449 match e.node {
e9174d1e
SL
450 hir::ExprUnary(..) |
451 hir::ExprBinary(..) |
452 hir::ExprIndex(..) if v.tcx.tables.borrow().method_map.contains_key(&method_call) => {
d9579d0f 453 v.add_qualif(ConstQualif::NOT_CONST);
85aaf69f 454 }
b039eaaf 455 hir::ExprBox(_) => {
d9579d0f 456 v.add_qualif(ConstQualif::NOT_CONST);
1a4d82fc 457 }
e9174d1e 458 hir::ExprUnary(op, ref inner) => {
c1a9b12d 459 match v.tcx.node_id_to_type(inner.id).sty {
62682a34 460 ty::TyRawPtr(_) => {
e9174d1e 461 assert!(op == hir::UnDeref);
62682a34 462
d9579d0f 463 v.add_qualif(ConstQualif::NOT_CONST);
85aaf69f
SL
464 }
465 _ => {}
223e47cc 466 }
1a4d82fc 467 }
e9174d1e 468 hir::ExprBinary(op, ref lhs, _) => {
c1a9b12d 469 match v.tcx.node_id_to_type(lhs.id).sty {
62682a34 470 ty::TyRawPtr(_) => {
e9174d1e
SL
471 assert!(op.node == hir::BiEq || op.node == hir::BiNe ||
472 op.node == hir::BiLe || op.node == hir::BiLt ||
473 op.node == hir::BiGe || op.node == hir::BiGt);
62682a34
SL
474
475 v.add_qualif(ConstQualif::NOT_CONST);
85aaf69f 476 }
62682a34 477 _ => {}
223e47cc 478 }
62682a34 479 }
e9174d1e 480 hir::ExprCast(ref from, _) => {
62682a34
SL
481 debug!("Checking const cast(id={})", from.id);
482 match v.tcx.cast_kinds.borrow().get(&from.id) {
54a0048b 483 None => span_bug!(e.span, "no kind for cast"),
62682a34
SL
484 Some(&CastKind::PtrAddrCast) | Some(&CastKind::FnPtrAddrCast) => {
485 v.add_qualif(ConstQualif::NOT_CONST);
85aaf69f 486 }
62682a34 487 _ => {}
223e47cc 488 }
1a4d82fc 489 }
e9174d1e 490 hir::ExprPath(..) => {
3157f602
XL
491 match v.tcx.expect_def(e.id) {
492 Def::Variant(..) => {
85aaf69f 493 // Count the discriminator or function pointer.
d9579d0f 494 v.add_qualif(ConstQualif::NON_ZERO_SIZED);
85aaf69f 495 }
3157f602 496 Def::Struct(..) => {
54a0048b 497 if let ty::TyFnDef(..) = node_ty.sty {
85aaf69f 498 // Count the function pointer.
d9579d0f 499 v.add_qualif(ConstQualif::NON_ZERO_SIZED);
85aaf69f
SL
500 }
501 }
3157f602 502 Def::Fn(..) | Def::Method(..) => {
85aaf69f 503 // Count the function pointer.
d9579d0f 504 v.add_qualif(ConstQualif::NON_ZERO_SIZED);
85aaf69f 505 }
3157f602 506 Def::Static(..) => {
85aaf69f
SL
507 match v.mode {
508 Mode::Static | Mode::StaticMut => {}
a7813a04 509 Mode::Const | Mode::ConstFn => {}
d9579d0f 510 Mode::Var => v.add_qualif(ConstQualif::NOT_CONST)
85aaf69f
SL
511 }
512 }
3157f602 513 Def::Const(did) | Def::AssociatedConst(did) => {
54a0048b
SL
514 let substs = Some(v.tcx.node_id_item_substs(e.id).substs);
515 if let Some((expr, _)) = lookup_const_by_id(v.tcx, did, substs) {
85aaf69f
SL
516 let inner = v.global_expr(Mode::Const, expr);
517 v.add_qualif(inner);
85aaf69f
SL
518 }
519 }
3157f602 520 Def::Local(..) if v.mode == Mode::ConstFn => {
62682a34
SL
521 // Sadly, we can't determine whether the types are zero-sized.
522 v.add_qualif(ConstQualif::NOT_CONST | ConstQualif::NON_ZERO_SIZED);
523 }
a7813a04 524 _ => {
d9579d0f 525 v.add_qualif(ConstQualif::NOT_CONST);
1a4d82fc 526 }
223e47cc 527 }
1a4d82fc 528 }
e9174d1e 529 hir::ExprCall(ref callee, _) => {
85aaf69f
SL
530 let mut callee = &**callee;
531 loop {
532 callee = match callee.node {
e9174d1e 533 hir::ExprBlock(ref block) => match block.expr {
7453a54e 534 Some(ref tail) => &tail,
85aaf69f
SL
535 None => break
536 },
537 _ => break
538 };
539 }
3157f602
XL
540 // The callee is an arbitrary expression, it doesn't necessarily have a definition.
541 let is_const = match v.tcx.expect_def_or_none(callee.id) {
7453a54e
SL
542 Some(Def::Struct(..)) => true,
543 Some(Def::Variant(..)) => {
85aaf69f 544 // Count the discriminator.
d9579d0f 545 v.add_qualif(ConstQualif::NON_ZERO_SIZED);
62682a34 546 true
85aaf69f 547 }
7453a54e 548 Some(Def::Fn(did)) => {
62682a34 549 v.handle_const_fn_call(e, did, node_ty)
223e47cc 550 }
7453a54e 551 Some(Def::Method(did)) => {
c1a9b12d
SL
552 match v.tcx.impl_or_trait_item(did).container() {
553 ty::ImplContainer(_) => {
554 v.handle_const_fn_call(e, did, node_ty)
555 }
556 ty::TraitContainer(_) => false
557 }
558 }
62682a34
SL
559 _ => false
560 };
561 if !is_const {
d9579d0f 562 v.add_qualif(ConstQualif::NOT_CONST);
62682a34
SL
563 }
564 }
e9174d1e 565 hir::ExprMethodCall(..) => {
c1a9b12d
SL
566 let method = v.tcx.tables.borrow().method_map[&method_call];
567 let is_const = match v.tcx.impl_or_trait_item(method.def_id).container() {
568 ty::ImplContainer(_) => v.handle_const_fn_call(e, method.def_id, node_ty),
569 ty::TraitContainer(_) => false
62682a34
SL
570 };
571 if !is_const {
572 v.add_qualif(ConstQualif::NOT_CONST);
223e47cc
LB
573 }
574 }
e9174d1e 575 hir::ExprStruct(..) => {
3157f602
XL
576 // unsafe_cell_type doesn't necessarily exist with no_core
577 if Some(v.tcx.expect_def(e.id).def_id()) == v.tcx.lang_items.unsafe_cell_type() {
d9579d0f 578 v.add_qualif(ConstQualif::MUTABLE_MEM);
85aaf69f
SL
579 }
580 }
581
e9174d1e
SL
582 hir::ExprLit(_) |
583 hir::ExprAddrOf(..) => {
d9579d0f 584 v.add_qualif(ConstQualif::NON_ZERO_SIZED);
85aaf69f
SL
585 }
586
e9174d1e 587 hir::ExprRepeat(..) => {
d9579d0f 588 v.add_qualif(ConstQualif::PREFER_IN_PLACE);
85aaf69f
SL
589 }
590
e9174d1e 591 hir::ExprClosure(..) => {
62682a34 592 // Paths in constant contexts cannot refer to local variables,
85aaf69f 593 // as there are none, and thus closures can't have upvars there.
c1a9b12d 594 if v.tcx.with_freevars(e.id, |fv| !fv.is_empty()) {
85aaf69f
SL
595 assert!(v.mode == Mode::Var,
596 "global closures can't capture anything");
d9579d0f 597 v.add_qualif(ConstQualif::NOT_CONST);
85aaf69f
SL
598 }
599 }
600
e9174d1e
SL
601 hir::ExprBlock(_) |
602 hir::ExprIndex(..) |
603 hir::ExprField(..) |
604 hir::ExprTupField(..) |
605 hir::ExprVec(_) |
9cc50fc6 606 hir::ExprType(..) |
e9174d1e 607 hir::ExprTup(..) => {}
85aaf69f
SL
608
609 // Conditional control flow (possible to implement).
e9174d1e
SL
610 hir::ExprMatch(..) |
611 hir::ExprIf(..) |
85aaf69f
SL
612
613 // Loops (not very meaningful in constants).
e9174d1e
SL
614 hir::ExprWhile(..) |
615 hir::ExprLoop(..) |
223e47cc 616
85aaf69f 617 // More control flow (also not very meaningful).
e9174d1e
SL
618 hir::ExprBreak(_) |
619 hir::ExprAgain(_) |
620 hir::ExprRet(_) |
223e47cc 621
62682a34 622 // Expressions with side-effects.
e9174d1e
SL
623 hir::ExprAssign(..) |
624 hir::ExprAssignOp(..) |
54a0048b 625 hir::ExprInlineAsm(..) => {
d9579d0f 626 v.add_qualif(ConstQualif::NOT_CONST);
223e47cc 627 }
85aaf69f
SL
628 }
629}
630
c1a9b12d 631/// Check the adjustments of an expression
e9174d1e 632fn check_adjustments<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr) {
c1a9b12d 633 match v.tcx.tables.borrow().adjustments.get(&e.id) {
e9174d1e 634 None |
5bcae85e 635 Some(&ty::adjustment::AdjustNeverToAny(..)) |
e9174d1e 636 Some(&ty::adjustment::AdjustReifyFnPointer) |
7453a54e
SL
637 Some(&ty::adjustment::AdjustUnsafeFnPointer) |
638 Some(&ty::adjustment::AdjustMutToConstPointer) => {}
e9174d1e 639
5bcae85e
SL
640 Some(&ty::adjustment::AdjustDerefRef(ty::adjustment::AutoDerefRef { autoderefs, .. })) => {
641 if (0..autoderefs as u32)
642 .any(|autoderef| v.tcx.is_overloaded_autoderef(e.id, autoderef)) {
c1a9b12d 643 v.add_qualif(ConstQualif::NOT_CONST);
c1a9b12d
SL
644 }
645 }
646 }
647}
648
a7813a04 649pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
5bcae85e
SL
650 tcx.visit_all_items_in_krate(DepNode::CheckConst,
651 &mut CheckCrateVisitor {
652 tcx: tcx,
653 mode: Mode::Var,
654 qualif: ConstQualif::NOT_CONST,
655 rvalue_borrows: NodeMap(),
656 });
85aaf69f
SL
657 tcx.sess.abort_if_errors();
658}
659
a7813a04 660impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for CheckCrateVisitor<'a, 'gcx> {
85aaf69f
SL
661 fn consume(&mut self,
662 _consume_id: ast::NodeId,
a7813a04 663 _consume_span: Span,
85aaf69f
SL
664 cmt: mc::cmt,
665 _mode: euv::ConsumeMode) {
666 let mut cur = &cmt;
667 loop {
668 match cur.cat {
92a42be0 669 Categorization::StaticItem => {
85aaf69f
SL
670 break;
671 }
9e0c209e 672 Categorization::Deref(ref cmt, ..) |
92a42be0
SL
673 Categorization::Downcast(ref cmt, _) |
674 Categorization::Interior(ref cmt, _) => cur = cmt,
85aaf69f 675
92a42be0
SL
676 Categorization::Rvalue(..) |
677 Categorization::Upvar(..) |
5bcae85e 678 Categorization::Local(..) => break,
85aaf69f
SL
679 }
680 }
681 }
682 fn borrow(&mut self,
683 borrow_id: ast::NodeId,
a7813a04 684 _borrow_span: Span,
85aaf69f 685 cmt: mc::cmt<'tcx>,
9e0c209e 686 _loan_region: &'tcx ty::Region,
85aaf69f 687 bk: ty::BorrowKind,
5bcae85e 688 loan_cause: euv::LoanCause) {
9346a6ac
AL
689 // Kind of hacky, but we allow Unsafe coercions in constants.
690 // These occur when we convert a &T or *T to a *U, as well as
691 // when making a thin pointer (e.g., `*T`) into a fat pointer
692 // (e.g., `*Trait`).
693 match loan_cause {
694 euv::LoanCause::AutoUnsafe => {
695 return;
696 }
5bcae85e 697 _ => {}
9346a6ac
AL
698 }
699
85aaf69f 700 let mut cur = &cmt;
85aaf69f
SL
701 loop {
702 match cur.cat {
92a42be0 703 Categorization::Rvalue(..) => {
85aaf69f
SL
704 if loan_cause == euv::MatchDiscriminant {
705 // Ignore the dummy immutable borrow created by EUV.
706 break;
707 }
708 let mutbl = bk.to_mutbl_lossy();
e9174d1e 709 if mutbl == hir::MutMutable && self.mode == Mode::StaticMut {
62682a34
SL
710 // Mutable slices are the only `&mut` allowed in
711 // globals, but only in `static mut`, nowhere else.
712 // FIXME: This exception is really weird... there isn't
713 // any fundamental reason to restrict this based on
714 // type of the expression. `&mut [1]` has exactly the
715 // same representation as &mut 1.
85aaf69f 716 match cmt.ty.sty {
9e0c209e 717 ty::TyArray(..) |
5bcae85e 718 ty::TySlice(_) => break,
85aaf69f
SL
719 _ => {}
720 }
721 }
722 self.record_borrow(borrow_id, mutbl);
723 break;
724 }
92a42be0 725 Categorization::StaticItem => {
85aaf69f
SL
726 break;
727 }
9e0c209e 728 Categorization::Deref(ref cmt, ..) |
92a42be0
SL
729 Categorization::Downcast(ref cmt, _) |
730 Categorization::Interior(ref cmt, _) => {
85aaf69f
SL
731 cur = cmt;
732 }
733
92a42be0 734 Categorization::Upvar(..) |
5bcae85e 735 Categorization::Local(..) => break,
85aaf69f
SL
736 }
737 }
223e47cc 738 }
85aaf69f 739
5bcae85e 740 fn decl_without_init(&mut self, _id: ast::NodeId, _span: Span) {}
85aaf69f
SL
741 fn mutate(&mut self,
742 _assignment_id: ast::NodeId,
743 _assignment_span: Span,
744 _assignee_cmt: mc::cmt,
5bcae85e
SL
745 _mode: euv::MutateMode) {
746 }
85aaf69f 747
5bcae85e 748 fn matched_pat(&mut self, _: &hir::Pat, _: mc::cmt, _: euv::MatchMode) {}
85aaf69f 749
5bcae85e 750 fn consume_pat(&mut self, _consume_pat: &hir::Pat, _cmt: mc::cmt, _mode: euv::ConsumeMode) {}
223e47cc 751}