]> git.proxmox.com Git - rustc.git/blobdiff - src/librustc_mir/transform/qualify_min_const_fn.rs
New upstream version 1.41.1+dfsg1
[rustc.git] / src / librustc_mir / transform / qualify_min_const_fn.rs
index c4e44091bc90d8f0049e3911ac751616768c4b03..e2530795749a9792befd39a985275161fa0341e2 100644 (file)
@@ -2,7 +2,6 @@ use rustc::hir::def_id::DefId;
 use rustc::hir;
 use rustc::mir::*;
 use rustc::ty::{self, Predicate, Ty, TyCtxt, adjustment::{PointerCast}};
-use rustc_target::spec::abi;
 use std::borrow::Cow;
 use syntax_pos::Span;
 use syntax::symbol::{sym, Symbol};
@@ -80,10 +79,14 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'a Body<'tcx>) -
 fn check_ty(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span, fn_def_id: DefId) -> McfResult {
     for ty in ty.walk() {
         match ty.kind {
-            ty::Ref(_, _, hir::Mutability::MutMutable) => return Err((
-                span,
-                "mutable references in const fn are unstable".into(),
-            )),
+            ty::Ref(_, _, hir::Mutability::Mutable) => {
+                if !feature_allowed(tcx, fn_def_id, sym::const_mut_refs) {
+                    return Err((
+                        span,
+                        "mutable references in const fn are unstable".into(),
+                    ))
+                }
+            }
             ty::Opaque(..) => return Err((span, "`impl Trait` in const fn is unstable".into())),
             ty::FnPtr(..) => {
                 if !tcx.const_fn_is_allowed_fn_ptr(fn_def_id) {
@@ -150,7 +153,8 @@ fn check_rvalue(
                 _ => check_operand(tcx, operand, span, def_id, body),
             }
         }
-        Rvalue::Cast(CastKind::Pointer(PointerCast::MutToConstPointer), operand, _) => {
+        Rvalue::Cast(CastKind::Pointer(PointerCast::MutToConstPointer), operand, _)
+        | Rvalue::Cast(CastKind::Pointer(PointerCast::ArrayToPointer), operand, _) => {
             check_operand(tcx, operand, span, def_id, body)
         }
         Rvalue::Cast(CastKind::Pointer(PointerCast::UnsafeFnPointer), _, _) |
@@ -215,14 +219,16 @@ fn check_statement(
             check_rvalue(tcx, body, def_id, rval, span)
         }
 
-        StatementKind::FakeRead(FakeReadCause::ForMatchedPlace, _) => {
+        | StatementKind::FakeRead(FakeReadCause::ForMatchedPlace, _)
+        if !feature_allowed(tcx, def_id, sym::const_if_match)
+        => {
             Err((span, "loops and conditional expressions are not stable in const fn".into()))
         }
 
         StatementKind::FakeRead(_, place) => check_place(tcx, place, span, def_id, body),
 
         // just an assignment
-        StatementKind::SetDiscriminant { .. } => Ok(()),
+        StatementKind::SetDiscriminant { place, .. } => check_place(tcx, place, span, def_id, body),
 
         | StatementKind::InlineAsm { .. } => {
             Err((span, "cannot use inline assembly in const fn".into()))
@@ -248,7 +254,10 @@ fn check_operand(
         Operand::Move(place) | Operand::Copy(place) => {
             check_place(tcx, place, span, def_id, body)
         }
-        Operand::Constant(_) => Ok(()),
+        Operand::Constant(c) => match c.check_static_ptr(tcx) {
+            Some(_) => Err((span, "cannot access `static` items in const fn".into())),
+            None => Ok(()),
+        },
     }
 }
 
@@ -263,9 +272,10 @@ fn check_place(
     while let &[ref proj_base @ .., elem] = cursor {
         cursor = proj_base;
         match elem {
-            ProjectionElem::Downcast(..) => {
-                return Err((span, "`match` or `if let` in `const fn` is unstable".into()));
-            }
+            ProjectionElem::Downcast(..) if !feature_allowed(tcx, def_id, sym::const_if_match)
+                => return Err((span, "`match` or `if let` in `const fn` is unstable".into())),
+            ProjectionElem::Downcast(_symbol, _variant_index) => {}
+
             ProjectionElem::Field(..) => {
                 let base_ty = Place::ty_from(&place.base, &proj_base, body, tcx).ty;
                 if let Some(def) = base_ty.ty_adt_def() {
@@ -284,13 +294,7 @@ fn check_place(
         }
     }
 
-    match place.base {
-        PlaceBase::Static(box Static { kind: StaticKind::Static, .. }) => {
-            Err((span, "cannot access `static` items in const fn".into()))
-        }
-        PlaceBase::Local(_)
-        | PlaceBase::Static(box Static { kind: StaticKind::Promoted(_, _), .. }) => Ok(()),
-    }
+    Ok(())
 }
 
 /// Returns whether `allow_internal_unstable(..., <feature_gate>, ...)` is present.
@@ -323,10 +327,22 @@ fn check_terminator(
             check_operand(tcx, value, span, def_id, body)
         },
 
-        TerminatorKind::FalseEdges { .. } | TerminatorKind::SwitchInt { .. } => Err((
+        | TerminatorKind::FalseEdges { .. }
+        | TerminatorKind::SwitchInt { .. }
+        if !feature_allowed(tcx, def_id, sym::const_if_match)
+        => Err((
             span,
             "loops and conditional expressions are not stable in const fn".into(),
         )),
+
+        TerminatorKind::FalseEdges { .. } => Ok(()),
+        TerminatorKind::SwitchInt { discr, switch_ty: _, values: _, targets: _ } => {
+            check_operand(tcx, discr, span, def_id, body)
+        }
+
+        // FIXME(ecstaticmorse): We probably want to allow `Unreachable` unconditionally.
+        TerminatorKind::Unreachable if feature_allowed(tcx, def_id, sym::const_if_match) => Ok(()),
+
         | TerminatorKind::Abort | TerminatorKind::Unreachable => {
             Err((span, "const fn with unreachable code is not stable".into()))
         }
@@ -343,18 +359,8 @@ fn check_terminator(
         } => {
             let fn_ty = func.ty(body, tcx);
             if let ty::FnDef(def_id, _) = fn_ty.kind {
-
-                // some intrinsics are waved through if called inside the
-                // standard library. Users never need to call them directly
-                match tcx.fn_sig(def_id).abi() {
-                    abi::Abi::RustIntrinsic => if !is_intrinsic_whitelisted(tcx, def_id) {
-                        return Err((
-                            span,
-                            "can only call a curated list of intrinsics in `min_const_fn`".into(),
-                        ))
-                    },
-                    abi::Abi::Rust if tcx.is_min_const_fn(def_id) => {},
-                    abi::Abi::Rust => return Err((
+                if !tcx.is_min_const_fn(def_id) {
+                    return Err((
                         span,
                         format!(
                             "can only call other `const fn` within a `const fn`, \
@@ -362,14 +368,7 @@ fn check_terminator(
                             func,
                         )
                         .into(),
-                    )),
-                    abi => return Err((
-                        span,
-                        format!(
-                            "cannot call functions with `{}` abi in `min_const_fn`",
-                            abi,
-                        ).into(),
-                    )),
+                    ));
                 }
 
                 check_operand(tcx, func, span, def_id, body)?;
@@ -391,40 +390,12 @@ fn check_terminator(
             cleanup: _,
         } => check_operand(tcx, cond, span, def_id, body),
 
+        | TerminatorKind::FalseUnwind { .. }
+        if feature_allowed(tcx, def_id, sym::const_loop)
+        => Ok(()),
+
         TerminatorKind::FalseUnwind { .. } => {
             Err((span, "loops are not allowed in const fn".into()))
-        },
-    }
-}
-
-/// Returns `true` if the `def_id` refers to an intrisic which we've whitelisted
-/// for being called from stable `const fn`s (`min_const_fn`).
-///
-/// Adding more intrinsics requires sign-off from @rust-lang/lang.
-fn is_intrinsic_whitelisted(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
-    match &tcx.item_name(def_id).as_str()[..] {
-        | "size_of"
-        | "min_align_of"
-        | "needs_drop"
-        // Arithmetic:
-        | "add_with_overflow" // ~> .overflowing_add
-        | "sub_with_overflow" // ~> .overflowing_sub
-        | "mul_with_overflow" // ~> .overflowing_mul
-        | "wrapping_add" // ~> .wrapping_add
-        | "wrapping_sub" // ~> .wrapping_sub
-        | "wrapping_mul" // ~> .wrapping_mul
-        | "saturating_add" // ~> .saturating_add
-        | "saturating_sub" // ~> .saturating_sub
-        | "unchecked_shl" // ~> .wrapping_shl
-        | "unchecked_shr" // ~> .wrapping_shr
-        | "rotate_left" // ~> .rotate_left
-        | "rotate_right" // ~> .rotate_right
-        | "ctpop" // ~> .count_ones
-        | "ctlz" // ~> .leading_zeros
-        | "cttz" // ~> .trailing_zeros
-        | "bswap" // ~> .swap_bytes
-        | "bitreverse" // ~> .reverse_bits
-        => true,
-        _ => false,
+        }
     }
 }