]> git.proxmox.com Git - rustc.git/blame - src/librustc_mir/transform/qualify_consts.rs
New upstream version 1.27.1+dfsg1
[rustc.git] / src / librustc_mir / transform / qualify_consts.rs
CommitLineData
a7813a04
XL
1// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
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
11//! A pass that qualifies constness of temporaries in constants,
12//! static initializers and functions and also drives promotion.
13//!
14//! The Qualif flags below can be used to also provide better
15//! diagnostics as to why a constant rvalue wasn't promoted.
16
17use rustc_data_structures::bitvec::BitVector;
ea8adc8c 18use rustc_data_structures::indexed_set::IdxSetBuf;
3157f602 19use rustc_data_structures::indexed_vec::{IndexVec, Idx};
2c00a5a8 20use rustc_data_structures::fx::FxHashSet;
a7813a04
XL
21use rustc::hir;
22use rustc::hir::def_id::DefId;
ea8adc8c 23use rustc::middle::const_val::ConstVal;
0531ce1d 24use rustc::traits::{self, TraitEngine};
8bb4bdeb 25use rustc::ty::{self, TyCtxt, Ty, TypeFoldable};
a7813a04 26use rustc::ty::cast::CastTy;
8bb4bdeb 27use rustc::ty::maps::Providers;
c30ab7b3
SL
28use rustc::mir::*;
29use rustc::mir::traversal::ReversePostorder;
ff7c6d11 30use rustc::mir::visit::{PlaceContext, Visitor};
476ff2be 31use rustc::middle::lang_items;
83c7162d 32use rustc_target::spec::abi::Abi;
ea8adc8c 33use syntax::attr;
2c00a5a8 34use syntax::ast::LitKind;
a7813a04 35use syntax::feature_gate::UnstableFeatures;
8bb4bdeb 36use syntax_pos::{Span, DUMMY_SP};
a7813a04 37
a7813a04 38use std::fmt;
0531ce1d 39use rustc_data_structures::sync::Lrc;
9e0c209e 40use std::usize;
a7813a04 41
abe05a73 42use transform::{MirPass, MirSource};
a7813a04
XL
43use super::promote_consts::{self, Candidate, TempState};
44
45bitflags! {
ff7c6d11
XL
46 // Borrows of temporaries can be promoted only if
47 // they have none of these qualifications, with
48 // the exception of `STATIC_REF` (in statics only).
ea8adc8c 49 struct Qualif: u8 {
a7813a04 50 // Constant containing interior mutability (UnsafeCell).
ea8adc8c 51 const MUTABLE_INTERIOR = 1 << 0;
a7813a04
XL
52
53 // Constant containing an ADT that implements Drop.
ea8adc8c 54 const NEEDS_DROP = 1 << 1;
a7813a04
XL
55
56 // Function argument.
ea8adc8c 57 const FN_ARGUMENT = 1 << 2;
a7813a04 58
ff7c6d11 59 // Static place or move from a static.
ea8adc8c 60 const STATIC = 1 << 3;
a7813a04
XL
61
62 // Reference to a static.
ea8adc8c 63 const STATIC_REF = 1 << 4;
a7813a04
XL
64
65 // Not constant at all - non-`const fn` calls, asm!,
66 // pointer comparisons, ptr-to-int casts, etc.
ea8adc8c 67 const NOT_CONST = 1 << 5;
a7813a04
XL
68
69 // Refers to temporaries which cannot be promoted as
70 // promote_consts decided they weren't simple enough.
ea8adc8c 71 const NOT_PROMOTABLE = 1 << 6;
a7813a04 72
a7813a04
XL
73 // Const items can only have MUTABLE_INTERIOR
74 // and NOT_PROMOTABLE without producing an error.
75 const CONST_ERROR = !Qualif::MUTABLE_INTERIOR.bits &
ea8adc8c 76 !Qualif::NOT_PROMOTABLE.bits;
a7813a04
XL
77 }
78}
79
80impl<'a, 'tcx> Qualif {
81 /// Remove flags which are impossible for the given type.
82 fn restrict(&mut self, ty: Ty<'tcx>,
83 tcx: TyCtxt<'a, 'tcx, 'tcx>,
7cac9316 84 param_env: ty::ParamEnv<'tcx>) {
cc61c64b 85 if ty.is_freeze(tcx, param_env, DUMMY_SP) {
a7813a04
XL
86 *self = *self - Qualif::MUTABLE_INTERIOR;
87 }
cc61c64b 88 if !ty.needs_drop(tcx, param_env) {
a7813a04
XL
89 *self = *self - Qualif::NEEDS_DROP;
90 }
91 }
92}
93
94/// What kind of item we are in.
95#[derive(Copy, Clone, PartialEq, Eq)]
96enum Mode {
97 Const,
98 Static,
99 StaticMut,
100 ConstFn,
101 Fn
102}
103
104impl fmt::Display for Mode {
105 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
106 match *self {
107 Mode::Const => write!(f, "constant"),
108 Mode::Static | Mode::StaticMut => write!(f, "static"),
109 Mode::ConstFn => write!(f, "constant function"),
110 Mode::Fn => write!(f, "function")
111 }
112 }
113}
114
a7813a04
XL
115struct Qualifier<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
116 mode: Mode,
117 span: Span,
118 def_id: DefId,
119 mir: &'a Mir<'tcx>,
120 rpo: ReversePostorder<'a, 'tcx>,
121 tcx: TyCtxt<'a, 'gcx, 'tcx>,
7cac9316 122 param_env: ty::ParamEnv<'tcx>,
c30ab7b3 123 temp_qualif: IndexVec<Local, Option<Qualif>>,
a7813a04
XL
124 return_qualif: Option<Qualif>,
125 qualif: Qualif,
126 const_fn_arg_vars: BitVector,
c30ab7b3 127 temp_promotion_state: IndexVec<Local, TempState>,
a7813a04
XL
128 promotion_candidates: Vec<Candidate>
129}
130
131impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
132 fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
a7813a04
XL
133 def_id: DefId,
134 mir: &'a Mir<'tcx>,
135 mode: Mode)
136 -> Qualifier<'a, 'tcx, 'tcx> {
137 let mut rpo = traversal::reverse_postorder(mir);
138 let temps = promote_consts::collect_temps(mir, &mut rpo);
139 rpo.reset();
2c00a5a8
XL
140
141 let param_env = tcx.param_env(def_id);
142
143 let mut temp_qualif = IndexVec::from_elem(None, &mir.local_decls);
144 for arg in mir.args_iter() {
145 let mut qualif = Qualif::NEEDS_DROP;
146 qualif.restrict(mir.local_decls[arg].ty, tcx, param_env);
147 temp_qualif[arg] = Some(qualif);
148 }
149
a7813a04 150 Qualifier {
3b2f2976 151 mode,
a7813a04 152 span: mir.span,
3b2f2976
XL
153 def_id,
154 mir,
155 rpo,
156 tcx,
2c00a5a8
XL
157 param_env,
158 temp_qualif,
a7813a04
XL
159 return_qualif: None,
160 qualif: Qualif::empty(),
c30ab7b3 161 const_fn_arg_vars: BitVector::new(mir.local_decls.len()),
a7813a04
XL
162 temp_promotion_state: temps,
163 promotion_candidates: vec![]
164 }
165 }
166
167 // FIXME(eddyb) we could split the errors into meaningful
168 // categories, but enabling full miri would make that
169 // slightly pointless (even with feature-gating).
170 fn not_const(&mut self) {
171 self.add(Qualif::NOT_CONST);
172 if self.mode != Mode::Fn {
2c00a5a8
XL
173 let mut err = struct_span_err!(
174 self.tcx.sess,
175 self.span,
176 E0019,
177 "{} contains unimplemented expression type",
178 self.mode
179 );
180 if self.tcx.sess.teach(&err.get_code().unwrap()) {
181 err.note("A function call isn't allowed in the const's initialization expression \
182 because the expression's value must be known at compile-time.");
183 err.note("Remember: you can't use a function call inside a const's initialization \
184 expression! However, you can use it anywhere else.");
185 }
186 err.emit();
a7813a04
XL
187 }
188 }
189
190 /// Error about extra statements in a constant.
191 fn statement_like(&mut self) {
192 self.add(Qualif::NOT_CONST);
193 if self.mode != Mode::Fn {
2c00a5a8
XL
194 let mut err = struct_span_err!(
195 self.tcx.sess,
196 self.span,
197 E0016,
198 "blocks in {}s are limited to items and tail expressions",
199 self.mode
200 );
201 if self.tcx.sess.teach(&err.get_code().unwrap()) {
202 err.note("Blocks in constants may only contain items (such as constant, function \
203 definition, etc...) and a tail expression.");
204 err.help("To avoid it, you have to replace the non-item object.");
205 }
206 err.emit();
a7813a04
XL
207 }
208 }
209
210 /// Add the given qualification to self.qualif.
211 fn add(&mut self, qualif: Qualif) {
212 self.qualif = self.qualif | qualif;
213 }
214
215 /// Add the given type's qualification to self.qualif.
216 fn add_type(&mut self, ty: Ty<'tcx>) {
217 self.add(Qualif::MUTABLE_INTERIOR | Qualif::NEEDS_DROP);
7cac9316 218 self.qualif.restrict(ty, self.tcx, self.param_env);
a7813a04
XL
219 }
220
221 /// Within the provided closure, self.qualif will start
222 /// out empty, and its value after the closure returns will
223 /// be combined with the value before the call to nest.
224 fn nest<F: FnOnce(&mut Self)>(&mut self, f: F) {
225 let original = self.qualif;
226 self.qualif = Qualif::empty();
227 f(self);
228 self.add(original);
229 }
230
ff7c6d11
XL
231 /// Check if a Local with the current qualifications is promotable.
232 fn can_promote(&mut self) -> bool {
233 // References to statics are allowed, but only in other statics.
234 if self.mode == Mode::Static || self.mode == Mode::StaticMut {
235 (self.qualif - Qualif::STATIC_REF).is_empty()
236 } else {
237 self.qualif.is_empty()
238 }
239 }
240
241 /// Check if a Place with the current qualifications could
a7813a04
XL
242 /// be consumed, by either an operand or a Deref projection.
243 fn try_consume(&mut self) -> bool {
244 if self.qualif.intersects(Qualif::STATIC) && self.mode != Mode::Fn {
245 let msg = if self.mode == Mode::Static ||
246 self.mode == Mode::StaticMut {
247 "cannot refer to other statics by value, use the \
248 address-of operator or a constant instead"
249 } else {
250 "cannot refer to statics by value, use a constant instead"
251 };
9e0c209e 252 struct_span_err!(self.tcx.sess, self.span, E0394, "{}", msg)
7cac9316
XL
253 .span_label(self.span, "referring to another static by value")
254 .note("use the address-of operator or a constant instead")
9e0c209e 255 .emit();
a7813a04
XL
256
257 // Replace STATIC with NOT_CONST to avoid further errors.
258 self.qualif = self.qualif - Qualif::STATIC;
259 self.add(Qualif::NOT_CONST);
260
261 false
262 } else {
263 true
264 }
265 }
266
267 /// Assign the current qualification to the given destination.
ff7c6d11 268 fn assign(&mut self, dest: &Place<'tcx>, location: Location) {
a7813a04
XL
269 let qualif = self.qualif;
270 let span = self.span;
271 let store = |slot: &mut Option<Qualif>| {
272 if slot.is_some() {
273 span_bug!(span, "multiple assignments to {:?}", dest);
274 }
275 *slot = Some(qualif);
276 };
277
278 // Only handle promotable temps in non-const functions.
279 if self.mode == Mode::Fn {
ff7c6d11 280 if let Place::Local(index) = *dest {
c30ab7b3
SL
281 if self.mir.local_kind(index) == LocalKind::Temp
282 && self.temp_promotion_state[index].is_promotable() {
283 debug!("store to promotable temp {:?}", index);
3157f602 284 store(&mut self.temp_qualif[index]);
a7813a04
XL
285 }
286 }
287 return;
288 }
289
290 match *dest {
ff7c6d11 291 Place::Local(index) if self.mir.local_kind(index) == LocalKind::Temp => {
c30ab7b3
SL
292 debug!("store to temp {:?}", index);
293 store(&mut self.temp_qualif[index])
294 }
ff7c6d11
XL
295 Place::Local(index) if self.mir.local_kind(index) == LocalKind::ReturnPointer => {
296 debug!("store to return place {:?}", index);
c30ab7b3
SL
297 store(&mut self.return_qualif)
298 }
a7813a04 299
ff7c6d11
XL
300 Place::Projection(box Projection {
301 base: Place::Local(index),
a7813a04 302 elem: ProjectionElem::Deref
c30ab7b3 303 }) if self.mir.local_kind(index) == LocalKind::Temp
32a655c1 304 && self.mir.local_decls[index].ty.is_box()
3157f602 305 && self.temp_qualif[index].map_or(false, |qualif| {
a7813a04
XL
306 qualif.intersects(Qualif::NOT_CONST)
307 }) => {
308 // Part of `box expr`, we should've errored
309 // already for the Box allocation Rvalue.
310 }
311
312 // This must be an explicit assignment.
313 _ => {
314 // Catch more errors in the destination.
ff7c6d11 315 self.visit_place(dest, PlaceContext::Store, location);
a7813a04
XL
316 self.statement_like();
317 }
318 }
319 }
320
a7813a04 321 /// Qualify a whole const, static initializer or const fn.
0531ce1d 322 fn qualify_const(&mut self) -> (Qualif, Lrc<IdxSetBuf<Local>>) {
7cac9316 323 debug!("qualifying {} {:?}", self.mode, self.def_id);
c30ab7b3 324
a7813a04
XL
325 let mir = self.mir;
326
3157f602 327 let mut seen_blocks = BitVector::new(mir.basic_blocks().len());
a7813a04
XL
328 let mut bb = START_BLOCK;
329 loop {
330 seen_blocks.insert(bb.index());
331
332 self.visit_basic_block_data(bb, &mir[bb]);
333
334 let target = match mir[bb].terminator().kind {
335 TerminatorKind::Goto { target } |
a7813a04 336 TerminatorKind::Drop { target, .. } |
3157f602 337 TerminatorKind::Assert { target, .. } |
a7813a04
XL
338 TerminatorKind::Call { destination: Some((_, target)), .. } => {
339 Some(target)
340 }
341
342 // Non-terminating calls cannot produce any value.
343 TerminatorKind::Call { destination: None, .. } => {
ea8adc8c 344 break;
a7813a04
XL
345 }
346
a7813a04 347 TerminatorKind::SwitchInt {..} |
3157f602
XL
348 TerminatorKind::DropAndReplace { .. } |
349 TerminatorKind::Resume |
ff7c6d11 350 TerminatorKind::Abort |
ea8adc8c
XL
351 TerminatorKind::GeneratorDrop |
352 TerminatorKind::Yield { .. } |
abe05a73 353 TerminatorKind::Unreachable |
2c00a5a8
XL
354 TerminatorKind::FalseEdges { .. } |
355 TerminatorKind::FalseUnwind { .. } => None,
a7813a04
XL
356
357 TerminatorKind::Return => {
358 // Check for unused values. This usually means
359 // there are extra statements in the AST.
c30ab7b3 360 for temp in mir.temps_iter() {
3157f602 361 if self.temp_qualif[temp].is_none() {
a7813a04
XL
362 continue;
363 }
364
3157f602 365 let state = self.temp_promotion_state[temp];
a7813a04
XL
366 if let TempState::Defined { location, uses: 0 } = state {
367 let data = &mir[location.block];
368 let stmt_idx = location.statement_index;
369
370 // Get the span for the initialization.
3157f602
XL
371 let source_info = if stmt_idx < data.statements.len() {
372 data.statements[stmt_idx].source_info
a7813a04 373 } else {
3157f602
XL
374 data.terminator().source_info
375 };
376 self.span = source_info.span;
a7813a04
XL
377
378 // Treat this as a statement in the AST.
379 self.statement_like();
380 }
381 }
382
383 // Make sure there are no extra unassigned variables.
384 self.qualif = Qualif::NOT_CONST;
c30ab7b3
SL
385 for index in mir.vars_iter() {
386 if !self.const_fn_arg_vars.contains(index.index()) {
387 debug!("unassigned variable {:?}", index);
ff7c6d11 388 self.assign(&Place::Local(index), Location {
9e0c209e
SL
389 block: bb,
390 statement_index: usize::MAX,
391 });
a7813a04
XL
392 }
393 }
394
395 break;
396 }
397 };
398
399 match target {
400 // No loops allowed.
401 Some(target) if !seen_blocks.contains(target.index()) => {
402 bb = target;
403 }
404 _ => {
405 self.not_const();
406 break;
407 }
408 }
409 }
410
a7813a04
XL
411 self.qualif = self.return_qualif.unwrap_or(Qualif::NOT_CONST);
412
ea8adc8c
XL
413 // Account for errors in consts by using the
414 // conservative type qualification instead.
415 if self.qualif.intersects(Qualif::CONST_ERROR) {
416 self.qualif = Qualif::empty();
abe05a73 417 let return_ty = mir.return_ty();
ea8adc8c
XL
418 self.add_type(return_ty);
419 }
420
421
422 // Collect all the temps we need to promote.
423 let mut promoted_temps = IdxSetBuf::new_empty(self.temp_promotion_state.len());
424
425 for candidate in &self.promotion_candidates {
426 match *candidate {
427 Candidate::Ref(Location { block: bb, statement_index: stmt_idx }) => {
428 match self.mir[bb].statements[stmt_idx].kind {
ff7c6d11 429 StatementKind::Assign(_, Rvalue::Ref(_, _, Place::Local(index))) => {
ea8adc8c
XL
430 promoted_temps.add(&index);
431 }
432 _ => {}
433 }
a7813a04 434 }
2c00a5a8 435 Candidate::Argument { .. } => {}
a7813a04
XL
436 }
437 }
ea8adc8c 438
0531ce1d 439 (self.qualif, Lrc::new(promoted_temps))
a7813a04
XL
440 }
441}
442
443/// Accumulates an Rvalue or Call's effects in self.qualif.
444/// For functions (constant or not), it also records
445/// candidates for promotion in promotion_candidates.
446impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
ea8adc8c
XL
447 fn visit_local(&mut self,
448 &local: &Local,
ff7c6d11 449 _: PlaceContext<'tcx>,
ea8adc8c 450 _: Location) {
2c00a5a8
XL
451 let kind = self.mir.local_kind(local);
452 match kind {
ea8adc8c
XL
453 LocalKind::ReturnPointer => {
454 self.not_const();
455 }
ea8adc8c
XL
456 LocalKind::Var => {
457 self.add(Qualif::NOT_CONST);
458 }
2c00a5a8 459 LocalKind::Arg |
ea8adc8c 460 LocalKind::Temp => {
2c00a5a8
XL
461 if let LocalKind::Arg = kind {
462 self.add(Qualif::FN_ARGUMENT);
463 }
464
ea8adc8c
XL
465 if !self.temp_promotion_state[local].is_promotable() {
466 self.add(Qualif::NOT_PROMOTABLE);
467 }
468
469 if let Some(qualif) = self.temp_qualif[local] {
470 self.add(qualif);
471 } else {
472 self.not_const();
473 }
474 }
475 }
476 }
477
ff7c6d11
XL
478 fn visit_place(&mut self,
479 place: &Place<'tcx>,
480 context: PlaceContext<'tcx>,
9e0c209e 481 location: Location) {
ff7c6d11
XL
482 match *place {
483 Place::Local(ref local) => self.visit_local(local, context, location),
484 Place::Static(ref global) => {
a7813a04 485 self.add(Qualif::STATIC);
3b2f2976
XL
486
487 if self.mode != Mode::Fn {
488 for attr in &self.tcx.get_attrs(global.def_id)[..] {
489 if attr.check_name("thread_local") {
490 span_err!(self.tcx.sess, self.span, E0625,
491 "thread-local statics cannot be \
492 accessed at compile-time");
ea8adc8c 493 self.add(Qualif::NOT_CONST);
3b2f2976
XL
494 return;
495 }
496 }
497 }
498
a7813a04 499 if self.mode == Mode::Const || self.mode == Mode::ConstFn {
2c00a5a8
XL
500 let mut err = struct_span_err!(self.tcx.sess, self.span, E0013,
501 "{}s cannot refer to statics, use \
502 a constant instead", self.mode);
503 if self.tcx.sess.teach(&err.get_code().unwrap()) {
504 err.note(
505 "Static and const variables can refer to other const variables. But a \
506 const variable cannot refer to a static variable."
507 );
508 err.help(
509 "To fix this, the value can be extracted as a const and then used."
510 );
511 }
512 err.emit()
a7813a04
XL
513 }
514 }
ff7c6d11 515 Place::Projection(ref proj) => {
a7813a04 516 self.nest(|this| {
ff7c6d11 517 this.super_place(place, context, location);
a7813a04
XL
518 match proj.elem {
519 ProjectionElem::Deref => {
520 if !this.try_consume() {
521 return;
522 }
523
524 if this.qualif.intersects(Qualif::STATIC_REF) {
525 this.qualif = this.qualif - Qualif::STATIC_REF;
526 this.add(Qualif::STATIC);
527 }
528
0531ce1d
XL
529 this.add(Qualif::NOT_CONST);
530
5bcae85e 531 let base_ty = proj.base.ty(this.mir, this.tcx).to_ty(this.tcx);
a7813a04 532 if let ty::TyRawPtr(_) = base_ty.sty {
a7813a04 533 if this.mode != Mode::Fn {
2c00a5a8
XL
534 let mut err = struct_span_err!(
535 this.tcx.sess,
536 this.span,
537 E0396,
9e0c209e 538 "raw pointers cannot be dereferenced in {}s",
2c00a5a8
XL
539 this.mode
540 );
541 err.span_label(this.span,
542 "dereference of raw pointer in constant");
543 if this.tcx.sess.teach(&err.get_code().unwrap()) {
544 err.note(
545 "The value behind a raw pointer can't be determined \
546 at compile-time (or even link-time), which means it \
547 can't be used in a constant expression."
548 );
549 err.help("A possible fix is to dereference your pointer \
550 at some point in run-time.");
551 }
552 err.emit();
a7813a04
XL
553 }
554 }
555 }
556
557 ProjectionElem::Field(..) |
558 ProjectionElem::Index(_) => {
83c7162d
XL
559 if this.mode == Mode::Fn {
560 let base_ty = proj.base.ty(this.mir, this.tcx).to_ty(this.tcx);
561 if let Some(def) = base_ty.ty_adt_def() {
562 if def.is_union() {
563 this.not_const();
564 }
565 }
566 } else if this.qualif.intersects(Qualif::STATIC) {
a7813a04
XL
567 span_err!(this.tcx.sess, this.span, E0494,
568 "cannot refer to the interior of another \
569 static, use a constant instead");
570 }
ff7c6d11 571 let ty = place.ty(this.mir, this.tcx).to_ty(this.tcx);
7cac9316 572 this.qualif.restrict(ty, this.tcx, this.param_env);
a7813a04
XL
573 }
574
575 ProjectionElem::ConstantIndex {..} |
3157f602 576 ProjectionElem::Subslice {..} |
a7813a04
XL
577 ProjectionElem::Downcast(..) => {
578 this.not_const()
579 }
580 }
581 });
582 }
583 }
584 }
585
9e0c209e 586 fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
a7813a04 587 match *operand {
2c00a5a8
XL
588 Operand::Copy(_) |
589 Operand::Move(_) => {
a7813a04 590 self.nest(|this| {
9e0c209e 591 this.super_operand(operand, location);
a7813a04
XL
592 this.try_consume();
593 });
ea8adc8c
XL
594
595 // Mark the consumed locals to indicate later drops are noops.
2c00a5a8
XL
596 if let Operand::Move(Place::Local(local)) = *operand {
597 self.temp_qualif[local] = self.temp_qualif[local].map(|q|
598 q - Qualif::NEEDS_DROP
599 );
ea8adc8c 600 }
a7813a04
XL
601 }
602 Operand::Constant(ref constant) => {
ea8adc8c
XL
603 if let Literal::Value {
604 value: &ty::Const { val: ConstVal::Unevaluated(def_id, _), ty }
605 } = constant.literal {
606 // Don't peek inside trait associated constants.
607 if self.tcx.trait_of_item(def_id).is_some() {
608 self.add_type(ty);
a7813a04 609 } else {
ea8adc8c 610 let (bits, _) = self.tcx.at(constant.span).mir_const_qualif(def_id);
a7813a04 611
8bb4bdeb
XL
612 let qualif = Qualif::from_bits(bits).expect("invalid mir_const_qualif");
613 self.add(qualif);
a7813a04 614
ea8adc8c
XL
615 // Just in case the type is more specific than
616 // the definition, e.g. impl associated const
617 // with type parameters, take it into account.
618 self.qualif.restrict(ty, self.tcx, self.param_env);
a7813a04
XL
619 }
620 }
621 }
622 }
623 }
624
9e0c209e 625 fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
ff7c6d11 626 // Recurse through operands and places.
0531ce1d
XL
627 if let Rvalue::Ref(region, kind, ref place) = *rvalue {
628 let mut is_reborrow = false;
629 if let Place::Projection(ref proj) = *place {
630 if let ProjectionElem::Deref = proj.elem {
631 let base_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx);
632 if let ty::TyRef(..) = base_ty.sty {
633 is_reborrow = true;
634 }
635 }
636 }
637
638 if is_reborrow {
639 self.nest(|this| {
640 this.super_place(place, PlaceContext::Borrow {
641 region,
642 kind
643 }, location);
644 if !this.try_consume() {
645 return;
646 }
647
648 if this.qualif.intersects(Qualif::STATIC_REF) {
649 this.qualif = this.qualif - Qualif::STATIC_REF;
650 this.add(Qualif::STATIC);
651 }
652 });
653 } else {
654 self.super_rvalue(rvalue, location);
655 }
656 } else {
657 self.super_rvalue(rvalue, location);
658 }
a7813a04
XL
659
660 match *rvalue {
661 Rvalue::Use(_) |
662 Rvalue::Repeat(..) |
7cac9316
XL
663 Rvalue::UnaryOp(UnOp::Neg, _) |
664 Rvalue::UnaryOp(UnOp::Not, _) |
665 Rvalue::NullaryOp(NullOp::SizeOf, _) |
3157f602 666 Rvalue::CheckedBinaryOp(..) |
9e0c209e
SL
667 Rvalue::Cast(CastKind::ReifyFnPointer, ..) |
668 Rvalue::Cast(CastKind::UnsafeFnPointer, ..) |
8bb4bdeb 669 Rvalue::Cast(CastKind::ClosureFnPointer, ..) |
cc61c64b
XL
670 Rvalue::Cast(CastKind::Unsize, ..) |
671 Rvalue::Discriminant(..) => {}
a7813a04
XL
672
673 Rvalue::Len(_) => {
ff7c6d11 674 // Static places in consts would have errored already,
a7813a04
XL
675 // don't treat length checks as reads from statics.
676 self.qualif = self.qualif - Qualif::STATIC;
677 }
678
ff7c6d11
XL
679 Rvalue::Ref(_, kind, ref place) => {
680 // Static places in consts would have errored already,
a7813a04
XL
681 // only keep track of references to them here.
682 if self.qualif.intersects(Qualif::STATIC) {
683 self.qualif = self.qualif - Qualif::STATIC;
684 self.add(Qualif::STATIC_REF);
685 }
686
ff7c6d11 687 let ty = place.ty(self.mir, self.tcx).to_ty(self.tcx);
2c00a5a8 688 if let BorrowKind::Mut { .. } = kind {
a7813a04
XL
689 // In theory, any zero-sized value could be borrowed
690 // mutably without consequences. However, only &mut []
691 // is allowed right now, and only in functions.
692 let allow = if self.mode == Mode::StaticMut {
693 // Inside a `static mut`, &mut [...] is also allowed.
694 match ty.sty {
ea8adc8c 695 ty::TyArray(..) | ty::TySlice(_) => true,
a7813a04
XL
696 _ => false
697 }
ea8adc8c 698 } else if let ty::TyArray(_, len) = ty.sty {
0531ce1d 699 len.val.unwrap_u64() == 0 &&
ea8adc8c 700 self.mode == Mode::Fn
a7813a04
XL
701 } else {
702 false
703 };
704
705 if !allow {
706 self.add(Qualif::NOT_CONST);
707 if self.mode != Mode::Fn {
2c00a5a8
XL
708 let mut err = struct_span_err!(self.tcx.sess, self.span, E0017,
709 "references in {}s may only refer \
710 to immutable values", self.mode);
711 err.span_label(self.span, format!("{}s require immutable values",
712 self.mode));
713 if self.tcx.sess.teach(&err.get_code().unwrap()) {
714 err.note("References in statics and constants may only refer to \
715 immutable values.\n\n\
716 Statics are shared everywhere, and if they refer to \
717 mutable data one might violate memory safety since \
718 holding multiple mutable references to shared data is \
719 not allowed.\n\n\
720 If you really want global mutable state, try using \
721 static mut or a global UnsafeCell.");
722 }
723 err.emit();
a7813a04
XL
724 }
725 }
726 } else {
727 // Constants cannot be borrowed if they contain interior mutability as
728 // it means that our "silent insertion of statics" could change
729 // initializer values (very bad).
730 if self.qualif.intersects(Qualif::MUTABLE_INTERIOR) {
731 // Replace MUTABLE_INTERIOR with NOT_CONST to avoid
732 // duplicate errors (from reborrowing, for example).
733 self.qualif = self.qualif - Qualif::MUTABLE_INTERIOR;
734 self.add(Qualif::NOT_CONST);
735 if self.mode != Mode::Fn {
736 span_err!(self.tcx.sess, self.span, E0492,
041b39d2 737 "cannot borrow a constant which may contain \
a7813a04
XL
738 interior mutability, create a static instead");
739 }
740 }
741 }
742
743 // We might have a candidate for promotion.
9e0c209e 744 let candidate = Candidate::Ref(location);
ff7c6d11 745 if self.can_promote() {
ea8adc8c 746 // We can only promote direct borrows of temps.
ff7c6d11 747 if let Place::Local(local) = *place {
ea8adc8c
XL
748 if self.mir.local_kind(local) == LocalKind::Temp {
749 self.promotion_candidates.push(candidate);
a7813a04
XL
750 }
751 }
752 }
753 }
754
755 Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) => {
5bcae85e 756 let operand_ty = operand.ty(self.mir, self.tcx);
a7813a04
XL
757 let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast");
758 let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
759 match (cast_in, cast_out) {
760 (CastTy::Ptr(_), CastTy::Int(_)) |
761 (CastTy::FnPtr, CastTy::Int(_)) => {
762 self.add(Qualif::NOT_CONST);
763 if self.mode != Mode::Fn {
2c00a5a8
XL
764 let mut err = struct_span_err!(
765 self.tcx.sess,
766 self.span,
767 E0018,
768 "raw pointers cannot be cast to integers in {}s",
769 self.mode
770 );
771 if self.tcx.sess.teach(&err.get_code().unwrap()) {
772 err.note("\
773The value of static and constant integers must be known at compile time. You can't cast a pointer \
774to an integer because the address of a pointer can vary.
775
776For example, if you write:
777
778```
779static MY_STATIC: u32 = 42;
780static MY_STATIC_ADDR: usize = &MY_STATIC as *const _ as usize;
781static WHAT: usize = (MY_STATIC_ADDR^17) + MY_STATIC_ADDR;
782```
783
784Then `MY_STATIC_ADDR` would contain the address of `MY_STATIC`. However, the address can change \
785when the program is linked, as well as change between different executions due to ASLR, and many \
786linkers would not be able to calculate the value of `WHAT`.
787
788On the other hand, static and constant pointers can point either to a known numeric address or to \
789the address of a symbol.
790
791```
792static MY_STATIC: u32 = 42;
793static MY_STATIC_ADDR: &'static u32 = &MY_STATIC;
794const CONST_ADDR: *const u8 = 0x5f3759df as *const u8;
795```
796
797This does not pose a problem by itself because they can't be accessed directly.");
798 }
799 err.emit();
a7813a04
XL
800 }
801 }
802 _ => {}
803 }
804 }
805
806 Rvalue::BinaryOp(op, ref lhs, _) => {
5bcae85e 807 if let ty::TyRawPtr(_) = lhs.ty(self.mir, self.tcx).sty {
a7813a04
XL
808 assert!(op == BinOp::Eq || op == BinOp::Ne ||
809 op == BinOp::Le || op == BinOp::Lt ||
7cac9316
XL
810 op == BinOp::Ge || op == BinOp::Gt ||
811 op == BinOp::Offset);
a7813a04
XL
812
813 self.add(Qualif::NOT_CONST);
814 if self.mode != Mode::Fn {
9e0c209e
SL
815 struct_span_err!(
816 self.tcx.sess, self.span, E0395,
817 "raw pointers cannot be compared in {}s",
818 self.mode)
819 .span_label(
820 self.span,
7cac9316 821 "comparing raw pointers in static")
9e0c209e 822 .emit();
a7813a04
XL
823 }
824 }
825 }
826
7cac9316 827 Rvalue::NullaryOp(NullOp::Box, _) => {
a7813a04
XL
828 self.add(Qualif::NOT_CONST);
829 if self.mode != Mode::Fn {
2c00a5a8
XL
830 let mut err = struct_span_err!(self.tcx.sess, self.span, E0010,
831 "allocations are not allowed in {}s", self.mode);
832 err.span_label(self.span, format!("allocation not allowed in {}s", self.mode));
833 if self.tcx.sess.teach(&err.get_code().unwrap()) {
834 err.note(
835 "The value of statics and constants must be known at compile time, \
836 and they live for the entire lifetime of a program. Creating a boxed \
837 value allocates memory on the heap at runtime, and therefore cannot \
838 be done at compile time."
839 );
840 }
841 err.emit();
a7813a04
XL
842 }
843 }
844
845 Rvalue::Aggregate(ref kind, _) => {
cc61c64b 846 if let AggregateKind::Adt(def, ..) = **kind {
8bb4bdeb 847 if def.has_dtor(self.tcx) {
a7813a04 848 self.add(Qualif::NEEDS_DROP);
a7813a04
XL
849 }
850
ea8adc8c 851 if Some(def.did) == self.tcx.lang_items().unsafe_cell_type() {
8bb4bdeb 852 let ty = rvalue.ty(self.mir, self.tcx);
a7813a04
XL
853 self.add_type(ty);
854 assert!(self.qualif.intersects(Qualif::MUTABLE_INTERIOR));
a7813a04
XL
855 }
856 }
857 }
a7813a04
XL
858 }
859 }
860
9e0c209e
SL
861 fn visit_terminator_kind(&mut self,
862 bb: BasicBlock,
863 kind: &TerminatorKind<'tcx>,
864 location: Location) {
a7813a04 865 if let TerminatorKind::Call { ref func, ref args, ref destination, .. } = *kind {
9e0c209e 866 self.visit_operand(func, location);
a7813a04 867
5bcae85e 868 let fn_ty = func.ty(self.mir, self.tcx);
2c00a5a8 869 let mut callee_def_id = None;
ea8adc8c 870 let (mut is_shuffle, mut is_const_fn) = (false, None);
3b2f2976 871 if let ty::TyFnDef(def_id, _) = fn_ty.sty {
2c00a5a8 872 callee_def_id = Some(def_id);
3b2f2976
XL
873 match self.tcx.fn_sig(def_id).abi() {
874 Abi::RustIntrinsic |
875 Abi::PlatformIntrinsic => {
876 assert!(!self.tcx.is_const_fn(def_id));
83c7162d 877 match &self.tcx.item_name(def_id).as_str()[..] {
2c00a5a8 878 "size_of" | "min_align_of" | "type_id" => is_const_fn = Some(def_id),
3b2f2976
XL
879
880 name if name.starts_with("simd_shuffle") => {
881 is_shuffle = true;
882 }
883
884 _ => {}
885 }
886 }
887 _ => {
ea8adc8c
XL
888 if self.tcx.is_const_fn(def_id) {
889 is_const_fn = Some(def_id);
890 }
3b2f2976 891 }
a7813a04 892 }
3b2f2976 893 }
a7813a04 894
2c00a5a8
XL
895 let constant_arguments = callee_def_id.and_then(|id| {
896 args_required_const(self.tcx, id)
897 });
a7813a04
XL
898 for (i, arg) in args.iter().enumerate() {
899 self.nest(|this| {
9e0c209e 900 this.visit_operand(arg, location);
2c00a5a8
XL
901 if this.mode != Mode::Fn {
902 return
903 }
904 let candidate = Candidate::Argument { bb, index: i };
905 if is_shuffle && i == 2 {
ff7c6d11 906 if this.can_promote() {
a7813a04
XL
907 this.promotion_candidates.push(candidate);
908 } else {
909 span_err!(this.tcx.sess, this.span, E0526,
910 "shuffle indices are not constant");
911 }
2c00a5a8
XL
912 return
913 }
914
915 let constant_arguments = match constant_arguments.as_ref() {
916 Some(s) => s,
917 None => return,
918 };
919 if !constant_arguments.contains(&i) {
920 return
921 }
922 if this.can_promote() {
923 this.promotion_candidates.push(candidate);
924 } else {
925 this.tcx.sess.span_err(this.span,
926 &format!("argument {} is required to be a constant",
927 i + 1));
a7813a04
XL
928 }
929 });
930 }
931
932 // Const fn calls.
ea8adc8c
XL
933 if let Some(def_id) = is_const_fn {
934 // find corresponding rustc_const_unstable feature
935 if let Some(&attr::Stability {
936 rustc_const_unstable: Some(attr::RustcConstUnstable {
937 feature: ref feature_name
938 }),
939 .. }) = self.tcx.lookup_stability(def_id) {
83c7162d 940 if
ea8adc8c 941 // feature-gate is not enabled,
0531ce1d 942 !self.tcx.features()
ea8adc8c
XL
943 .declared_lib_features
944 .iter()
945 .any(|&(ref sym, _)| sym == feature_name) &&
946
947 // this doesn't come from a crate with the feature-gate enabled,
948 self.def_id.is_local() &&
949
950 // this doesn't come from a macro that has #[allow_internal_unstable]
951 !self.span.allows_unstable()
952 {
83c7162d
XL
953 self.qualif = Qualif::NOT_CONST;
954 if self.mode != Mode::Fn {
955 // inside a constant environment, not having the feature gate is
956 // an error
957 let mut err = self.tcx.sess.struct_span_err(self.span,
958 &format!("`{}` is not yet stable as a const fn",
959 self.tcx.item_path_str(def_id)));
960 help!(&mut err,
961 "in Nightly builds, add `#![feature({})]` \
962 to the crate attributes to enable",
963 feature_name);
964 err.emit();
965 }
ea8adc8c 966 }
a7813a04
XL
967 }
968 } else {
969 self.qualif = Qualif::NOT_CONST;
970 if self.mode != Mode::Fn {
971 // FIXME(#24111) Remove this check when const fn stabilizes
972 let (msg, note) = if let UnstableFeatures::Disallow =
973 self.tcx.sess.opts.unstable_features {
974 (format!("calls in {}s are limited to \
83c7162d 975 tuple structs and tuple variants",
a7813a04
XL
976 self.mode),
977 Some("a limited form of compile-time function \
978 evaluation is available on a nightly \
979 compiler via `const fn`"))
980 } else {
981 (format!("calls in {}s are limited \
982 to constant functions, \
83c7162d 983 tuple structs and tuple variants",
a7813a04
XL
984 self.mode),
985 None)
986 };
987 let mut err = struct_span_err!(self.tcx.sess, self.span, E0015, "{}", msg);
988 if let Some(note) = note {
989 err.span_note(self.span, note);
990 }
991 err.emit();
992 }
993 }
994
995 if let Some((ref dest, _)) = *destination {
996 // Avoid propagating irrelevant callee/argument qualifications.
997 if self.qualif.intersects(Qualif::CONST_ERROR) {
998 self.qualif = Qualif::NOT_CONST;
999 } else {
1000 // Be conservative about the returned value of a const fn.
1001 let tcx = self.tcx;
5bcae85e 1002 let ty = dest.ty(self.mir, tcx).to_ty(tcx);
a7813a04
XL
1003 self.qualif = Qualif::empty();
1004 self.add_type(ty);
ea8adc8c
XL
1005 }
1006 self.assign(dest, location);
1007 }
ff7c6d11 1008 } else if let TerminatorKind::Drop { location: ref place, .. } = *kind {
ea8adc8c 1009 self.super_terminator_kind(bb, kind, location);
a7813a04 1010
ea8adc8c
XL
1011 // Deny *any* live drops anywhere other than functions.
1012 if self.mode != Mode::Fn {
1013 // HACK(eddyb) Emulate a bit of dataflow analysis,
1014 // conservatively, that drop elaboration will do.
ff7c6d11 1015 let needs_drop = if let Place::Local(local) = *place {
2c00a5a8
XL
1016 if self.temp_qualif[local].map_or(true, |q| q.intersects(Qualif::NEEDS_DROP)) {
1017 Some(self.mir.local_decls[local].source_info.span)
1018 } else {
1019 None
1020 }
ea8adc8c 1021 } else {
2c00a5a8 1022 Some(self.span)
ea8adc8c
XL
1023 };
1024
1025 if let Some(span) = needs_drop {
1026 // Double-check the type being dropped, to minimize false positives.
ff7c6d11 1027 let ty = place.ty(self.mir, self.tcx).to_ty(self.tcx);
ea8adc8c
XL
1028 if ty.needs_drop(self.tcx, self.param_env) {
1029 struct_span_err!(self.tcx.sess, span, E0493,
1030 "destructors cannot be evaluated at compile-time")
1031 .span_label(span, format!("{}s cannot evaluate destructors",
1032 self.mode))
1033 .emit();
a7813a04
XL
1034 }
1035 }
a7813a04
XL
1036 }
1037 } else {
1038 // Qualify any operands inside other terminators.
9e0c209e 1039 self.super_terminator_kind(bb, kind, location);
a7813a04
XL
1040 }
1041 }
1042
9e0c209e
SL
1043 fn visit_assign(&mut self,
1044 _: BasicBlock,
ff7c6d11 1045 dest: &Place<'tcx>,
9e0c209e
SL
1046 rvalue: &Rvalue<'tcx>,
1047 location: Location) {
1048 self.visit_rvalue(rvalue, location);
a7813a04
XL
1049
1050 // Check the allowed const fn argument forms.
ff7c6d11 1051 if let (Mode::ConstFn, &Place::Local(index)) = (self.mode, dest) {
c30ab7b3
SL
1052 if self.mir.local_kind(index) == LocalKind::Var &&
1053 self.const_fn_arg_vars.insert(index.index()) {
1054
a7813a04 1055 // Direct use of an argument is permitted.
ff7c6d11
XL
1056 match *rvalue {
1057 Rvalue::Use(Operand::Copy(Place::Local(local))) |
1058 Rvalue::Use(Operand::Move(Place::Local(local))) => {
1059 if self.mir.local_kind(local) == LocalKind::Arg {
1060 return;
1061 }
c30ab7b3 1062 }
ff7c6d11 1063 _ => {}
a7813a04
XL
1064 }
1065
1066 // Avoid a generic error for other uses of arguments.
1067 if self.qualif.intersects(Qualif::FN_ARGUMENT) {
c30ab7b3 1068 let decl = &self.mir.local_decls[index];
2c00a5a8
XL
1069 let mut err = struct_span_err!(
1070 self.tcx.sess,
1071 decl.source_info.span,
1072 E0022,
1073 "arguments of constant functions can only be immutable by-value bindings"
1074 );
1075 if self.tcx.sess.teach(&err.get_code().unwrap()) {
1076 err.note("Constant functions are not allowed to mutate anything. Thus, \
1077 binding to an argument with a mutable pattern is not allowed.");
1078 err.note("Remove any mutable bindings from the argument list to fix this \
1079 error. In case you need to mutate the argument, try lazily \
1080 initializing a global variable instead of using a const fn, or \
1081 refactoring the code to a functional style to avoid mutation if \
1082 possible.");
1083 }
1084 err.emit();
a7813a04
XL
1085 return;
1086 }
1087 }
1088 }
1089
9e0c209e 1090 self.assign(dest, location);
a7813a04
XL
1091 }
1092
3157f602
XL
1093 fn visit_source_info(&mut self, source_info: &SourceInfo) {
1094 self.span = source_info.span;
1095 }
1096
9e0c209e 1097 fn visit_statement(&mut self, bb: BasicBlock, statement: &Statement<'tcx>, location: Location) {
5bcae85e
SL
1098 self.nest(|this| {
1099 this.visit_source_info(&statement.source_info);
1100 match statement.kind {
ff7c6d11
XL
1101 StatementKind::Assign(ref place, ref rvalue) => {
1102 this.visit_assign(bb, place, rvalue, location);
5bcae85e
SL
1103 }
1104 StatementKind::SetDiscriminant { .. } |
1105 StatementKind::StorageLive(_) |
9e0c209e 1106 StatementKind::StorageDead(_) |
8bb4bdeb 1107 StatementKind::InlineAsm {..} |
041b39d2 1108 StatementKind::EndRegion(_) |
3b2f2976 1109 StatementKind::Validate(..) |
0531ce1d 1110 StatementKind::UserAssertTy(..) |
9e0c209e 1111 StatementKind::Nop => {}
5bcae85e
SL
1112 }
1113 });
a7813a04
XL
1114 }
1115
9e0c209e
SL
1116 fn visit_terminator(&mut self,
1117 bb: BasicBlock,
1118 terminator: &Terminator<'tcx>,
1119 location: Location) {
1120 self.nest(|this| this.super_terminator(bb, terminator, location));
a7813a04
XL
1121 }
1122}
1123
8bb4bdeb 1124pub fn provide(providers: &mut Providers) {
7cac9316
XL
1125 *providers = Providers {
1126 mir_const_qualif,
1127 ..*providers
1128 };
8bb4bdeb
XL
1129}
1130
7cac9316
XL
1131fn mir_const_qualif<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
1132 def_id: DefId)
0531ce1d 1133 -> (u8, Lrc<IdxSetBuf<Local>>) {
7cac9316
XL
1134 // NB: This `borrow()` is guaranteed to be valid (i.e., the value
1135 // cannot yet be stolen), because `mir_validated()`, which steals
1136 // from `mir_const(), forces this query to execute before
1137 // performing the steal.
1138 let mir = &tcx.mir_const(def_id).borrow();
1139
abe05a73 1140 if mir.return_ty().references_error() {
ea8adc8c 1141 tcx.sess.delay_span_bug(mir.span, "mir_const_qualif: Mir had errors");
0531ce1d 1142 return (Qualif::NOT_CONST.bits(), Lrc::new(IdxSetBuf::new_empty(0)));
a7813a04
XL
1143 }
1144
ea8adc8c
XL
1145 let mut qualifier = Qualifier::new(tcx, def_id, mir, Mode::Const);
1146 let (qualif, promoted_temps) = qualifier.qualify_const();
1147 (qualif.bits(), promoted_temps)
a7813a04
XL
1148}
1149
8bb4bdeb 1150pub struct QualifyAndPromoteConstants;
a7813a04 1151
7cac9316
XL
1152impl MirPass for QualifyAndPromoteConstants {
1153 fn run_pass<'a, 'tcx>(&self,
1154 tcx: TyCtxt<'a, 'tcx, 'tcx>,
1155 src: MirSource,
1156 mir: &mut Mir<'tcx>) {
ea8adc8c 1157 // There's not really any point in promoting errorful MIR.
abe05a73 1158 if mir.return_ty().references_error() {
ea8adc8c
XL
1159 tcx.sess.delay_span_bug(mir.span, "QualifyAndPromoteConstants: Mir had errors");
1160 return;
1161 }
1162
abe05a73
XL
1163 if src.promoted.is_some() {
1164 return;
1165 }
1166
1167 let def_id = src.def_id;
1168 let id = tcx.hir.as_local_node_id(def_id).unwrap();
ea8adc8c 1169 let mut const_promoted_temps = None;
abe05a73
XL
1170 let mode = match tcx.hir.body_owner_kind(id) {
1171 hir::BodyOwnerKind::Fn => {
041b39d2 1172 if tcx.is_const_fn(def_id) {
c30ab7b3
SL
1173 Mode::ConstFn
1174 } else {
1175 Mode::Fn
1176 }
a7813a04 1177 }
abe05a73 1178 hir::BodyOwnerKind::Const => {
ea8adc8c
XL
1179 const_promoted_temps = Some(tcx.mir_const_qualif(def_id).1);
1180 Mode::Const
1181 }
abe05a73
XL
1182 hir::BodyOwnerKind::Static(hir::MutImmutable) => Mode::Static,
1183 hir::BodyOwnerKind::Static(hir::MutMutable) => Mode::StaticMut,
c30ab7b3 1184 };
c30ab7b3
SL
1185
1186 if mode == Mode::Fn || mode == Mode::ConstFn {
1187 // This is ugly because Qualifier holds onto mir,
1188 // which can't be mutated until its scope ends.
1189 let (temps, candidates) = {
ea8adc8c 1190 let mut qualifier = Qualifier::new(tcx, def_id, mir, mode);
c30ab7b3
SL
1191 if mode == Mode::ConstFn {
1192 // Enforce a constant-like CFG for `const fn`.
1193 qualifier.qualify_const();
1194 } else {
1195 while let Some((bb, data)) = qualifier.rpo.next() {
1196 qualifier.visit_basic_block_data(bb, data);
a7813a04 1197 }
c30ab7b3 1198 }
a7813a04 1199
c30ab7b3
SL
1200 (qualifier.temp_promotion_state, qualifier.promotion_candidates)
1201 };
a7813a04 1202
c30ab7b3
SL
1203 // Do the actual promotion, now that we know what's viable.
1204 promote_consts::promote_candidates(mir, tcx, temps, candidates);
1205 } else {
ea8adc8c
XL
1206 let promoted_temps = if mode == Mode::Const {
1207 // Already computed by `mir_const_qualif`.
1208 const_promoted_temps.unwrap()
1209 } else {
1210 Qualifier::new(tcx, def_id, mir, mode).qualify_const().1
1211 };
1212
1213 // In `const` and `static` everything without `StorageDead`
1214 // is `'static`, we don't have to create promoted MIR fragments,
1215 // just remove `Drop` and `StorageDead` on "promoted" locals.
1216 for block in mir.basic_blocks_mut() {
1217 block.statements.retain(|statement| {
1218 match statement.kind {
1219 StatementKind::StorageDead(index) => {
1220 !promoted_temps.contains(&index)
1221 }
1222 _ => true
1223 }
1224 });
1225 let terminator = block.terminator_mut();
1226 match terminator.kind {
ff7c6d11 1227 TerminatorKind::Drop { location: Place::Local(index), target, .. } => {
ea8adc8c
XL
1228 if promoted_temps.contains(&index) {
1229 terminator.kind = TerminatorKind::Goto {
1230 target,
1231 };
1232 }
1233 }
1234 _ => {}
1235 }
1236 }
c30ab7b3 1237 }
3157f602 1238
c30ab7b3
SL
1239 // Statics must be Sync.
1240 if mode == Mode::Static {
3b2f2976
XL
1241 // `#[thread_local]` statics don't have to be `Sync`.
1242 for attr in &tcx.get_attrs(def_id)[..] {
1243 if attr.check_name("thread_local") {
1244 return;
1245 }
1246 }
abe05a73 1247 let ty = mir.return_ty();
041b39d2 1248 tcx.infer_ctxt().enter(|infcx| {
0531ce1d 1249 let param_env = ty::ParamEnv::empty();
c30ab7b3
SL
1250 let cause = traits::ObligationCause::new(mir.span, id, traits::SharedStatic);
1251 let mut fulfillment_cx = traits::FulfillmentContext::new();
7cac9316
XL
1252 fulfillment_cx.register_bound(&infcx,
1253 param_env,
1254 ty,
476ff2be
SL
1255 tcx.require_lang_item(lang_items::SyncTraitLangItem),
1256 cause);
c30ab7b3 1257 if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) {
0531ce1d 1258 infcx.report_fulfillment_errors(&err, None, false);
c30ab7b3
SL
1259 }
1260 });
a7813a04
XL
1261 }
1262 }
1263}
2c00a5a8
XL
1264
1265fn args_required_const(tcx: TyCtxt, def_id: DefId) -> Option<FxHashSet<usize>> {
1266 let attrs = tcx.get_attrs(def_id);
1267 let attr = attrs.iter().find(|a| a.check_name("rustc_args_required_const"))?;
1268 let mut ret = FxHashSet();
1269 for meta in attr.meta_item_list()? {
1270 match meta.literal()?.node {
1271 LitKind::Int(a, _) => { ret.insert(a as usize); }
1272 _ => return None,
1273 }
1274 }
1275 Some(ret)
1276}