]> git.lizzy.rs Git - rust.git/commitdiff
Implement the `min_const_fn` feature gate
authorOliver Schneider <git-spam-no-reply9815368754983@oli-obk.de>
Wed, 22 Aug 2018 13:56:37 +0000 (15:56 +0200)
committerOliver Schneider <github35764891676564198441@oli-obk.de>
Fri, 31 Aug 2018 06:39:59 +0000 (08:39 +0200)
39 files changed:
src/libcore/mem.rs
src/librustc/ich/impls_mir.rs
src/librustc/ich/impls_syntax.rs
src/librustc/middle/stability.rs
src/librustc/mir/mod.rs
src/librustc/ty/context.rs
src/librustc_mir/hair/cx/mod.rs
src/librustc_mir/transform/check_unsafety.rs
src/librustc_mir/transform/mod.rs
src/librustc_mir/transform/qualify_consts.rs
src/librustc_mir/transform/qualify_min_const_fn.rs [new file with mode: 0644]
src/librustc_passes/rvalue_promotion.rs
src/librustc_typeck/check/intrinsic.rs
src/librustc_typeck/collect.rs
src/libstd/io/lazy.rs
src/libstd/io/stdio.rs
src/libsyntax/attr/builtin.rs
src/libsyntax/attr/mod.rs
src/libsyntax/feature_gate.rs
src/test/mir-opt/lower_128bit_test.rs
src/test/run-pass/invalid_const_promotion.rs
src/test/ui/consts/const-size_of-cycle.stderr
src/test/ui/consts/min_const_fn/min_const_fn.nll.stderr [new file with mode: 0644]
src/test/ui/consts/min_const_fn/min_const_fn.rs [new file with mode: 0644]
src/test/ui/consts/min_const_fn/min_const_fn.stderr [new file with mode: 0644]
src/test/ui/consts/min_const_fn/min_const_fn_dyn.nll.stderr [new file with mode: 0644]
src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs [new file with mode: 0644]
src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr [new file with mode: 0644]
src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.rs [new file with mode: 0644]
src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.stderr [new file with mode: 0644]
src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs [new file with mode: 0644]
src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr [new file with mode: 0644]
src/test/ui/consts/min_const_fn/min_const_fn_unsafe.rs [new file with mode: 0644]
src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr [new file with mode: 0644]
src/test/ui/error-codes/E0308.stderr
src/test/ui/feature-gates/feature-gate-const_fn.rs
src/test/ui/feature-gates/feature-gate-const_fn.stderr
src/test/ui/feature-gates/feature-gate-min_const_fn.rs [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-min_const_fn.stderr [new file with mode: 0644]

index f2852d98282b7be7df5cecdc89b52bbaa4523398..e00a22bf8b6c360674bcd3ec5da5573e49cb0cf6 100644 (file)
@@ -285,6 +285,15 @@ pub fn forget<T>(t: T) {
 /// [alignment]: ./fn.align_of.html
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[cfg(not(stage0))]
+pub const fn size_of<T>() -> usize {
+    intrinsics::size_of::<T>()
+}
+
+#[inline]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg(stage0)]
+/// Ceci n'est pas la documentation
 pub const fn size_of<T>() -> usize {
     unsafe { intrinsics::size_of::<T>() }
 }
@@ -334,6 +343,16 @@ pub fn size_of_val<T: ?Sized>(val: &T) -> usize {
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_deprecated(reason = "use `align_of` instead", since = "1.2.0")]
+#[cfg(not(stage0))]
+pub fn min_align_of<T>() -> usize {
+    intrinsics::min_align_of::<T>()
+}
+
+#[inline]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_deprecated(reason = "use `align_of` instead", since = "1.2.0")]
+#[cfg(stage0)]
+/// Ceci n'est pas la documentation
 pub fn min_align_of<T>() -> usize {
     unsafe { intrinsics::min_align_of::<T>() }
 }
@@ -376,6 +395,15 @@ pub fn min_align_of_val<T: ?Sized>(val: &T) -> usize {
 /// ```
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[cfg(not(stage0))]
+pub const fn align_of<T>() -> usize {
+    intrinsics::min_align_of::<T>()
+}
+
+#[inline]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg(stage0)]
+/// Ceci n'est pas la documentation
 pub const fn align_of<T>() -> usize {
     unsafe { intrinsics::min_align_of::<T>() }
 }
index 1c9387d02d5a34ffbc3de811e20e9e365b7c8cca..f11e4487964624d74ce17abd7aa57a3d0b0846e9 100644 (file)
@@ -65,6 +65,7 @@ fn hash_stable<W: StableHasherResult>(&self,
 
         match *self {
             mir::UnsafetyViolationKind::General => {}
+            mir::UnsafetyViolationKind::MinConstFn => {}
             mir::UnsafetyViolationKind::ExternStatic(lint_node_id) |
             mir::UnsafetyViolationKind::BorrowPacked(lint_node_id) => {
                 lint_node_id.hash_stable(hcx, hasher);
index ac5fdb2fe27971f980261a54b5d3cc11b8205379..a15411c7d83698c115b8bb5dc8f8a5531e22a0ae 100644 (file)
@@ -130,7 +130,7 @@ fn to_stable_hash_key(&self,
     level,
     feature,
     rustc_depr,
-    rustc_const_unstable
+    const_stability
 });
 
 impl<'a> HashStable<StableHashingContext<'a>>
@@ -161,7 +161,6 @@ fn hash_stable<W: StableHasherResult>(&self,
 }
 
 impl_stable_hash_for!(struct ::syntax::attr::RustcDeprecation { since, reason });
-impl_stable_hash_for!(struct ::syntax::attr::RustcConstUnstable { feature });
 
 
 impl_stable_hash_for!(enum ::syntax::attr::IntType {
index 85195b0f62e7cf58aeaaaaf3e8b55e4880c7f38f..f237c5b397bd5263722c7ab089f0760ac12a605f 100644 (file)
@@ -440,7 +440,7 @@ pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Index<'tcx> {
                     },
                     feature: Symbol::intern("rustc_private"),
                     rustc_depr: None,
-                    rustc_const_unstable: None,
+                    const_stability: None,
                 });
                 annotator.parent_stab = Some(stability);
             }
index 0840f333c876b1ec6e95af8074a5bc8bf1e7889a..0e60d6565176ad7da452fcf1ff72410a3dff9a1d 100644 (file)
@@ -2394,6 +2394,8 @@ pub fn dominates(&self, other: Location, dominators: &Dominators<BasicBlock>) ->
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
 pub enum UnsafetyViolationKind {
     General,
+    /// unsafety is not allowed at all in min const fn
+    MinConstFn,
     ExternStatic(ast::NodeId),
     BorrowPacked(ast::NodeId),
 }
index de50598c42c9da5774b02538806ab483193cfe27..6981d92f05f00cf9ec4c96acf9e99d4adccf19e9 100644 (file)
@@ -1099,6 +1099,37 @@ fn is_global(self) -> bool {
         local as usize == global as usize
     }
 
+    /// Returns true if this function must conform to `min_const_fn`
+    pub fn is_min_const_fn(self, def_id: DefId) -> bool {
+        if self.features().staged_api {
+            // some intrinsics are waved through if called inside the
+            // standard library. Users never need to call them directly
+            if let abi::Abi::RustIntrinsic = self.fn_sig(def_id).abi() {
+                assert!(!self.is_const_fn(def_id));
+                match &self.item_name(def_id).as_str()[..] {
+                    | "size_of"
+                    | "min_align_of"
+                    => return true,
+                    _ => {},
+                }
+            }
+            // in order for a libstd function to be considered min_const_fn
+            // it needs to be stable and have no `rustc_const_unstable` attribute
+            match self.lookup_stability(def_id) {
+                // stable functions with unstable const fn aren't `min_const_fn`
+                Some(&attr::Stability { const_stability: Some(_), .. }) => false,
+                // unstable functions don't need to conform
+                Some(&attr::Stability { ref level, .. }) if level.is_unstable() => false,
+                // everything else needs to conform, because it would be callable from
+                // other `min_const_fn` functions
+                _ => true,
+            }
+        } else {
+            // users enabling the `const_fn` can do what they want
+            !self.sess.features_untracked().const_fn
+        }
+    }
+
     /// Create a type context and call the closure with a `TyCtxt` reference
     /// to the context. The closure enforces that the type context and any interned
     /// value (types, substs, etc.) can only be used while `ty::tls` has a valid
index c9fd1d04e547b7f0a8a8b1d4a1e9562cc00c3dbc..b4257a40e38af0dd0ea3ff3de467b5d4cd080ca6 100644 (file)
@@ -18,7 +18,6 @@
 
 use rustc_data_structures::indexed_vec::Idx;
 use rustc::hir::def_id::{DefId, LOCAL_CRATE};
-use rustc::hir::map::blocks::FnLikeNode;
 use rustc::hir::Node;
 use rustc::middle::region;
 use rustc::infer::InferCtxt;
@@ -67,10 +66,7 @@ pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
         let constness = match body_owner_kind {
             hir::BodyOwnerKind::Const |
             hir::BodyOwnerKind::Static(_) => hir::Constness::Const,
-            hir::BodyOwnerKind::Fn => {
-                let fn_like = FnLikeNode::from_node(infcx.tcx.hir.get(src_id));
-                fn_like.map_or(hir::Constness::NotConst, |f| f.constness())
-            }
+            hir::BodyOwnerKind::Fn => hir::Constness::NotConst,
         };
 
         let attrs = tcx.hir.attrs(src_id);
@@ -83,7 +79,7 @@ pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
         // Respect -C overflow-checks.
         check_overflow |= tcx.sess.overflow_checks();
 
-        // Constants and const fn's always need overflow checks.
+        // Constants always need overflow checks.
         check_overflow |= constness == hir::Constness::Const;
 
         let lint_level = lint_level_for_hir_id(tcx, src_id);
index f6006ae045ee787e238d520d2c2836378fafab30..ec7fd371a442bb8ca406751b2953587379eb3173 100644 (file)
@@ -28,6 +28,7 @@
 
 pub struct UnsafetyChecker<'a, 'tcx: 'a> {
     mir: &'a Mir<'tcx>,
+    min_const_fn: bool,
     source_scope_local_data: &'a IndexVec<SourceScope, SourceScopeLocalData>,
     violations: Vec<UnsafetyViolation>,
     source_info: SourceInfo,
@@ -38,12 +39,16 @@ pub struct UnsafetyChecker<'a, 'tcx: 'a> {
 }
 
 impl<'a, 'gcx, 'tcx> UnsafetyChecker<'a, 'tcx> {
-    fn new(mir: &'a Mir<'tcx>,
-           source_scope_local_data: &'a IndexVec<SourceScope, SourceScopeLocalData>,
-           tcx: TyCtxt<'a, 'tcx, 'tcx>,
-           param_env: ty::ParamEnv<'tcx>) -> Self {
+    fn new(
+        min_const_fn: bool,
+        mir: &'a Mir<'tcx>,
+        source_scope_local_data: &'a IndexVec<SourceScope, SourceScopeLocalData>,
+        tcx: TyCtxt<'a, 'tcx, 'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+    ) -> Self {
         Self {
             mir,
+            min_const_fn,
             source_scope_local_data,
             violations: vec![],
             source_info: SourceInfo {
@@ -269,6 +274,15 @@ fn require_unsafe(&mut self,
     fn register_violations(&mut self,
                            violations: &[UnsafetyViolation],
                            unsafe_blocks: &[(ast::NodeId, bool)]) {
+        if self.min_const_fn {
+            for violation in violations {
+                let mut violation = violation.clone();
+                violation.kind = UnsafetyViolationKind::MinConstFn;
+                if !self.violations.contains(&violation) {
+                    self.violations.push(violation)
+                }
+            }
+        }
         let within_unsafe = match self.source_scope_local_data[self.source_info.scope].safety {
             Safety::Safe => {
                 for violation in violations {
@@ -276,7 +290,6 @@ fn register_violations(&mut self,
                         self.violations.push(violation.clone())
                     }
                 }
-
                 false
             }
             Safety::BuiltinUnsafe | Safety::FnUnsafe => true,
@@ -369,6 +382,7 @@ fn unsafety_check_result<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
 
     let param_env = tcx.param_env(def_id);
     let mut checker = UnsafetyChecker::new(
+        tcx.is_const_fn(def_id) && tcx.is_min_const_fn(def_id),
         mir, source_scope_local_data, tcx, param_env);
     checker.visit_mir(mir);
 
@@ -478,6 +492,15 @@ pub fn check_unsafety<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) {
                     .note(&details.as_str()[..])
                     .emit();
             }
+            UnsafetyViolationKind::MinConstFn => {
+                tcx.sess.struct_span_err(
+                    source_info.span,
+                    &format!("{} is unsafe and unsafe operations \
+                            are not allowed in const fn", description))
+                    .span_label(source_info.span, &description.as_str()[..])
+                    .note(&details.as_str()[..])
+                    .emit();
+            }
             UnsafetyViolationKind::ExternStatic(lint_node_id) => {
                 tcx.lint_node_note(SAFE_EXTERN_STATICS,
                               lint_node_id,
index 90dfebeef1b0ca7b0bb194b1bc46d3808e2ca251..1e05b07030ef898436f6740b9ebce4076a11d749 100644 (file)
@@ -36,6 +36,7 @@
 pub mod add_call_guards;
 pub mod promote_consts;
 pub mod qualify_consts;
+mod qualify_min_const_fn;
 pub mod remove_noop_landing_pads;
 pub mod dump_mir;
 pub mod deaggregator;
index 36dcd1714716cdd67a2df18b64e017ae5c7c1a43..c696318d283cecd87d26e0d3b52fa69cc52ce11b 100644 (file)
@@ -916,9 +916,7 @@ fn visit_terminator_kind(&mut self,
                         );
                     }
                 } else if let Some(&attr::Stability {
-                    rustc_const_unstable: Some(attr::RustcConstUnstable {
-                        feature: ref feature_name
-                    }),
+                    const_stability: Some(ref feature_name),
                 .. }) = self.tcx.lookup_stability(def_id) {
                     if
                         // feature-gate is not enabled,
@@ -1175,8 +1173,20 @@ fn run_pass<'a, 'tcx>(&self,
             let (temps, candidates) = {
                 let mut qualifier = Qualifier::new(tcx, def_id, mir, mode);
                 if mode == Mode::ConstFn {
-                    // Enforce a constant-like CFG for `const fn`.
-                    qualifier.qualify_const();
+                    if tcx.is_min_const_fn(def_id) {
+                        // enforce `min_const_fn` for stable const fns
+                        use super::qualify_min_const_fn::is_min_const_fn;
+                        if let Err((span, err)) = is_min_const_fn(tcx, def_id, mir) {
+                            tcx.sess.span_err(span, &err);
+                        } else {
+                            // this should not produce any errors, but better safe than sorry
+                            // FIXME(#53819)
+                            qualifier.qualify_const();
+                        }
+                    } else {
+                        // Enforce a constant-like CFG for `const fn`.
+                        qualifier.qualify_const();
+                    }
                 } else {
                     while let Some((bb, data)) = qualifier.rpo.next() {
                         qualifier.visit_basic_block_data(bb, data);
diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs
new file mode 100644 (file)
index 0000000..53ba4b0
--- /dev/null
@@ -0,0 +1,378 @@
+use rustc::hir::def_id::DefId;
+use rustc::hir;
+use rustc::mir::*;
+use rustc::ty::{self, Predicate, TyCtxt};
+use std::borrow::Cow;
+use syntax_pos::Span;
+
+mod helper {
+    pub struct IsMinConstFn(());
+    /// This should only ever be used *once* and then passed around as a token.
+    pub fn ensure_that_you_really_intended_to_create_an_instance_of_this() -> IsMinConstFn {
+        IsMinConstFn(())
+    }
+}
+
+use self::helper::*;
+
+type McfResult = Result<IsMinConstFn, (Span, Cow<'static, str>)>;
+
+pub fn is_min_const_fn(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    def_id: DefId,
+    mir: &'a Mir<'tcx>,
+) -> McfResult {
+    let mut current = def_id;
+    loop {
+        let predicates = tcx.predicates_of(current);
+        for predicate in &predicates.predicates {
+            match predicate {
+                | Predicate::RegionOutlives(_)
+                | Predicate::TypeOutlives(_)
+                | Predicate::WellFormed(_)
+                | Predicate::ConstEvaluatable(..) => continue,
+                | Predicate::ObjectSafe(_) => {
+                    bug!("object safe predicate on function: {:#?}", predicate)
+                }
+                Predicate::ClosureKind(..) => {
+                    bug!("closure kind predicate on function: {:#?}", predicate)
+                }
+                Predicate::Subtype(_) => bug!("subtype predicate on function: {:#?}", predicate),
+                Predicate::Projection(_) => {
+                    let span = tcx.def_span(current);
+                    // we'll hit a `Predicate::Trait` later which will report an error
+                    tcx.sess
+                        .delay_span_bug(span, "projection without trait bound");
+                    continue;
+                }
+                Predicate::Trait(pred) => {
+                    if Some(pred.def_id()) == tcx.lang_items().sized_trait() {
+                        continue;
+                    }
+                    match pred.skip_binder().self_ty().sty {
+                        ty::Param(ref p) => {
+                            let generics = tcx.generics_of(current);
+                            let def = generics.type_param(p, tcx);
+                            let span = tcx.def_span(def.def_id);
+                            return Err((
+                                span,
+                                "trait bounds other than `Sized` \
+                                 on const fn parameters are unstable"
+                                    .into(),
+                            ));
+                        }
+                        // other kinds of bounds are either tautologies
+                        // or cause errors in other passes
+                        _ => continue,
+                    }
+                }
+            }
+        }
+        match predicates.parent {
+            Some(parent) => current = parent,
+            None => break,
+        }
+    }
+
+    let mut token = ensure_that_you_really_intended_to_create_an_instance_of_this();
+
+    for local in mir.vars_iter() {
+        return Err((
+            mir.local_decls[local].source_info.span,
+            "local variables in const fn are unstable".into(),
+        ));
+    }
+    for local in &mir.local_decls {
+        token = check_ty(tcx, local.ty, local.source_info.span, token)?;
+    }
+    // impl trait is gone in MIR, so check the return type manually
+    token = check_ty(
+        tcx,
+        tcx.fn_sig(def_id).output().skip_binder(),
+        mir.local_decls.iter().next().unwrap().source_info.span,
+        token,
+    )?;
+
+    for bb in mir.basic_blocks() {
+        token = check_terminator(tcx, mir, bb.terminator(), token)?;
+        for stmt in &bb.statements {
+            token = check_statement(tcx, mir, stmt, token)?;
+        }
+    }
+    Ok(token)
+}
+
+fn check_ty(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    ty: ty::Ty<'tcx>,
+    span: Span,
+    token: IsMinConstFn,
+) -> McfResult {
+    for ty in ty.walk() {
+        match ty.sty {
+            ty::Ref(_, _, hir::Mutability::MutMutable) => return Err((
+                span,
+                "mutable references in const fn are unstable".into(),
+            )),
+            ty::Anon(..) => return Err((span, "`impl Trait` in const fn is unstable".into())),
+            ty::FnPtr(..) => {
+                return Err((span, "function pointers in const fn are unstable".into()))
+            }
+            ty::Dynamic(preds, _) => {
+                for pred in preds.iter() {
+                    match pred.skip_binder() {
+                        | ty::ExistentialPredicate::AutoTrait(_)
+                        | ty::ExistentialPredicate::Projection(_) => {
+                            return Err((
+                                span,
+                                "trait bounds other than `Sized` \
+                                 on const fn parameters are unstable"
+                                    .into(),
+                            ))
+                        }
+                        ty::ExistentialPredicate::Trait(trait_ref) => {
+                            if Some(trait_ref.def_id) != tcx.lang_items().sized_trait() {
+                                return Err((
+                                    span,
+                                    "trait bounds other than `Sized` \
+                                     on const fn parameters are unstable"
+                                        .into(),
+                                ));
+                            }
+                        }
+                    }
+                }
+            }
+            _ => {}
+        }
+    }
+    Ok(token)
+}
+
+fn check_rvalue(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    mir: &'a Mir<'tcx>,
+    rvalue: &Rvalue<'tcx>,
+    span: Span,
+    token: IsMinConstFn,
+) -> McfResult {
+    match rvalue {
+        Rvalue::Repeat(operand, _) | Rvalue::Use(operand) => {
+            check_operand(tcx, mir, operand, span, token)
+        }
+        Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) => {
+            check_place(tcx, mir, place, span, token, PlaceMode::Read)
+        }
+        Rvalue::Cast(_, operand, cast_ty) => {
+            use rustc::ty::cast::CastTy;
+            let cast_in = CastTy::from_ty(operand.ty(mir, tcx)).expect("bad input type for cast");
+            let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
+            match (cast_in, cast_out) {
+                (CastTy::Ptr(_), CastTy::Int(_)) | (CastTy::FnPtr, CastTy::Int(_)) => Err((
+                    span,
+                    "casting pointers to ints is unstable in const fn".into(),
+                )),
+                (CastTy::RPtr(_), CastTy::Float) => bug!(),
+                (CastTy::RPtr(_), CastTy::Int(_)) => bug!(),
+                (CastTy::Ptr(_), CastTy::RPtr(_)) => bug!(),
+                _ => check_operand(tcx, mir, operand, span, token),
+            }
+        }
+        // binops are fine on integers
+        Rvalue::BinaryOp(_, lhs, rhs) | Rvalue::CheckedBinaryOp(_, lhs, rhs) => {
+            let token = check_operand(tcx, mir, lhs, span, token)?;
+            let token = check_operand(tcx, mir, rhs, span, token)?;
+            let ty = lhs.ty(mir, tcx);
+            if ty.is_integral() || ty.is_bool() || ty.is_char() {
+                Ok(token)
+            } else {
+                Err((
+                    span,
+                    "only int, `bool` and `char` operations are stable in const fn".into(),
+                ))
+            }
+        }
+        // checked by regular const fn checks
+        Rvalue::NullaryOp(..) => Ok(token),
+        Rvalue::UnaryOp(_, operand) => {
+            let ty = operand.ty(mir, tcx);
+            if ty.is_integral() || ty.is_bool() {
+                check_operand(tcx, mir, operand, span, token)
+            } else {
+                Err((
+                    span,
+                    "only int and `bool` operations are stable in const fn".into(),
+                ))
+            }
+        }
+        Rvalue::Aggregate(_, operands) => {
+            let mut token = token;
+            for operand in operands {
+                token = check_operand(tcx, mir, operand, span, token)?;
+            }
+            Ok(token)
+        }
+    }
+}
+
+enum PlaceMode {
+    Assign,
+    Read,
+}
+
+fn check_statement(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    mir: &'a Mir<'tcx>,
+    statement: &Statement<'tcx>,
+    token: IsMinConstFn,
+) -> McfResult {
+    let span = statement.source_info.span;
+    match &statement.kind {
+        StatementKind::Assign(place, rval) => {
+            let token = check_place(tcx, mir, place, span, token, PlaceMode::Assign)?;
+            check_rvalue(tcx, mir, rval, span, token)
+        }
+
+        StatementKind::ReadForMatch(_) => Err((span, "match in const fn is unstable".into())),
+
+        // just an assignment
+        StatementKind::SetDiscriminant { .. } => Ok(token),
+
+        | StatementKind::InlineAsm { .. } => {
+            Err((span, "cannot use inline assembly in const fn".into()))
+        }
+
+        // These are all NOPs
+        | StatementKind::StorageLive(_)
+        | StatementKind::StorageDead(_)
+        | StatementKind::Validate(..)
+        | StatementKind::EndRegion(_)
+        | StatementKind::UserAssertTy(..)
+        | StatementKind::Nop => Ok(token),
+    }
+}
+
+fn check_operand(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    mir: &'a Mir<'tcx>,
+    operand: &Operand<'tcx>,
+    span: Span,
+    token: IsMinConstFn,
+) -> McfResult {
+    match operand {
+        Operand::Move(place) | Operand::Copy(place) => {
+            check_place(tcx, mir, place, span, token, PlaceMode::Read)
+        }
+        Operand::Constant(_) => Ok(token),
+    }
+}
+
+fn check_place(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    mir: &'a Mir<'tcx>,
+    place: &Place<'tcx>,
+    span: Span,
+    token: IsMinConstFn,
+    mode: PlaceMode,
+) -> McfResult {
+    match place {
+        Place::Local(l) => match mode {
+            PlaceMode::Assign => match mir.local_kind(*l) {
+                LocalKind::Temp | LocalKind::ReturnPointer => Ok(token),
+                LocalKind::Arg | LocalKind::Var => {
+                    Err((span, "assignments in const fn are unstable".into()))
+                }
+            },
+            PlaceMode::Read => Ok(token),
+        },
+        // promoteds are always fine, they are essentially constants
+        Place::Promoted(_) => Ok(token),
+        Place::Static(_) => Err((span, "cannot access `static` items in const fn".into())),
+        Place::Projection(proj) => {
+            match proj.elem {
+                | ProjectionElem::Deref | ProjectionElem::Field(..) | ProjectionElem::Index(_) => {
+                    check_place(tcx, mir, &proj.base, span, token, mode)
+                }
+                // slice patterns are unstable
+                | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {
+                    return Err((span, "slice patterns in const fn are unstable".into()))
+                }
+                | ProjectionElem::Downcast(..) => {
+                    Err((span, "`match` or `if let` in `const fn` is unstable".into()))
+                }
+            }
+        }
+    }
+}
+
+fn check_terminator(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    mir: &'a Mir<'tcx>,
+    terminator: &Terminator<'tcx>,
+    token: IsMinConstFn,
+) -> McfResult {
+    let span = terminator.source_info.span;
+    match &terminator.kind {
+        | TerminatorKind::Goto { .. }
+        | TerminatorKind::Return
+        | TerminatorKind::Resume => Ok(token),
+
+        TerminatorKind::Drop { location, .. } => {
+            check_place(tcx, mir, location, span, token, PlaceMode::Read)
+        }
+        TerminatorKind::DropAndReplace { location, value, .. } => {
+            let token = check_place(tcx, mir, location, span, token, PlaceMode::Read)?;
+            check_operand(tcx, mir, value, span, token)
+        },
+        TerminatorKind::SwitchInt { .. } => Err((
+            span,
+            "`if`, `match`, `&&` and `||` are not stable in const fn".into(),
+        )),
+        | TerminatorKind::Abort | TerminatorKind::Unreachable => {
+            Err((span, "const fn with unreachable code is not stable".into()))
+        }
+        | TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => {
+            Err((span, "const fn generators are unstable".into()))
+        }
+
+        TerminatorKind::Call {
+            func,
+            args,
+            destination: _,
+            cleanup: _,
+        } => {
+            let fn_ty = func.ty(mir, tcx);
+            if let ty::FnDef(def_id, _) = fn_ty.sty {
+                if tcx.is_min_const_fn(def_id) {
+                    let mut token = check_operand(tcx, mir, func, span, token)?;
+
+                    for arg in args {
+                        token = check_operand(tcx, mir, arg, span, token)?;
+                    }
+                    Ok(token)
+                } else {
+                    Err((
+                        span,
+                        "can only call other `min_const_fn` within a `min_const_fn`".into(),
+                    ))
+                }
+            } else {
+                Err((span, "can only call other const fns within const fn".into()))
+            }
+        }
+
+        TerminatorKind::Assert {
+            cond,
+            expected: _,
+            msg: _,
+            target: _,
+            cleanup: _,
+        } => check_operand(tcx, mir, cond, span, token),
+
+        | TerminatorKind::FalseEdges { .. } | TerminatorKind::FalseUnwind { .. } => span_bug!(
+            terminator.source_info.span,
+            "min_const_fn encountered `{:#?}`",
+            terminator
+        ),
+    }
+}
index fca1c7f27ab37a590274385579ca5b7cf94a2efe..f9f74b77e6c46347386fbbf08edab0570986d24d 100644 (file)
@@ -178,9 +178,7 @@ fn handle_const_fn_call(&mut self, def_id: DefId,
         }
 
         if let Some(&attr::Stability {
-            rustc_const_unstable: Some(attr::RustcConstUnstable {
-                                           feature: ref feature_name
-                                       }),
+            const_stability: Some(ref feature_name),
             .. }) = self.tcx.lookup_stability(def_id) {
             let stable_check =
                 // feature-gate is enabled,
index 23872ddf2f64b8c836d12fdd4fbbfc31012e5611..c7db3debf5a0d6dfacd6b276249715e1202d0a95 100644 (file)
 
 use std::iter;
 
-fn equate_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                   it: &hir::ForeignItem,
-                                   n_tps: usize,
-                                   abi: Abi,
-                                   inputs: Vec<Ty<'tcx>>,
-                                   output: Ty<'tcx>) {
+fn equate_intrinsic_type<'a, 'tcx>(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    it: &hir::ForeignItem,
+    n_tps: usize,
+    abi: Abi,
+    safety: hir::Unsafety,
+    inputs: Vec<Ty<'tcx>>,
+    output: Ty<'tcx>,
+) {
     let def_id = tcx.hir.local_def_id(it.id);
 
     match it.node {
@@ -65,7 +68,7 @@ fn equate_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         inputs.into_iter(),
         output,
         false,
-        hir::Unsafety::Unsafe,
+        safety,
         abi
     )));
     let cause = ObligationCause::new(it.span, it.id, ObligationCauseCode::IntrinsicType);
@@ -78,7 +81,7 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                       it: &hir::ForeignItem) {
     let param = |n| tcx.mk_ty_param(n, Symbol::intern(&format!("P{}", n)).as_interned_str());
     let name = it.name.as_str();
-    let (n_tps, inputs, output) = if name.starts_with("atomic_") {
+    let (n_tps, inputs, output, unsafety) = if name.starts_with("atomic_") {
         let split : Vec<&str> = name.split('_').collect();
         assert!(split.len() >= 2, "Atomic intrinsic not correct format");
 
@@ -109,10 +112,14 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 return;
             }
         };
-        (n_tps, inputs, output)
+        (n_tps, inputs, output, hir::Unsafety::Unsafe)
     } else if &name[..] == "abort" || &name[..] == "unreachable" {
-        (0, Vec::new(), tcx.types.never)
+        (0, Vec::new(), tcx.types.never, hir::Unsafety::Unsafe)
     } else {
+        let unsafety = match &name[..] {
+            "size_of" | "min_align_of" => hir::Unsafety::Normal,
+            _ => hir::Unsafety::Unsafe,
+        };
         let (n_tps, inputs, output) = match &name[..] {
             "breakpoint" => (0, Vec::new(), tcx.mk_nil()),
             "size_of" |
@@ -327,9 +334,9 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 return;
             }
         };
-        (n_tps, inputs, output)
+        (n_tps, inputs, output, unsafety)
     };
-    equate_intrinsic_type(tcx, it, n_tps, Abi::RustIntrinsic, inputs, output)
+    equate_intrinsic_type(tcx, it, n_tps, Abi::RustIntrinsic, unsafety, inputs, output)
 }
 
 /// Type-check `extern "platform-intrinsic" { ... }` functions.
@@ -439,7 +446,7 @@ pub fn check_platform_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         }
     };
 
-    equate_intrinsic_type(tcx, it, n_tps, Abi::PlatformIntrinsic,
+    equate_intrinsic_type(tcx, it, n_tps, Abi::PlatformIntrinsic, hir::Unsafety::Unsafe,
                           inputs, output)
 }
 
index a42667ab45fc8726993b72d44000b4054f6ff702..b956c72b3a2da53c0d8fde1b847165a1a108b7ac 100644 (file)
@@ -1981,12 +1981,15 @@ fn compute_sig_of_foreign_fn_decl<'a, 'tcx>(
     decl: &hir::FnDecl,
     abi: abi::Abi,
 ) -> ty::PolyFnSig<'tcx> {
-    let fty = AstConv::ty_of_fn(
-        &ItemCtxt::new(tcx, def_id),
-        hir::Unsafety::Unsafe,
-        abi,
-        decl,
-    );
+    let unsafety = if abi == abi::Abi::RustIntrinsic {
+        match &*tcx.item_name(def_id).as_str() {
+            "size_of" | "min_align_of" => hir::Unsafety::Normal,
+            _ => hir::Unsafety::Unsafe,
+        }
+    } else {
+        hir::Unsafety::Unsafe
+    };
+    let fty = AstConv::ty_of_fn(&ItemCtxt::new(tcx, def_id), unsafety, abi, decl);
 
     // feature gate SIMD types in FFI, since I (huonw) am not sure the
     // ABIs are handled at all correctly.
index 4fb367fb6ba524147e9a1806d02eab4759a8d0b6..24965ff69318435e874eaad52f9dc8a1b58edcc3 100644 (file)
@@ -18,7 +18,6 @@ pub struct Lazy<T> {
     // We never call `lock.init()`, so it is UB to attempt to acquire this mutex reentrantly!
     lock: Mutex,
     ptr: Cell<*mut Arc<T>>,
-    init: fn() -> Arc<T>,
 }
 
 #[inline]
@@ -26,33 +25,32 @@ const fn done<T>() -> *mut Arc<T> { 1_usize as *mut _ }
 
 unsafe impl<T> Sync for Lazy<T> {}
 
-impl<T: Send + Sync + 'static> Lazy<T> {
-    /// Safety: `init` must not call `get` on the variable that is being
-    /// initialized.
-    pub const unsafe fn new(init: fn() -> Arc<T>) -> Lazy<T> {
+impl<T> Lazy<T> {
+    pub const fn new() -> Lazy<T> {
         Lazy {
             lock: Mutex::new(),
             ptr: Cell::new(ptr::null_mut()),
-            init,
         }
     }
+}
 
-    pub fn get(&'static self) -> Option<Arc<T>> {
-        unsafe {
-            let _guard = self.lock.lock();
-            let ptr = self.ptr.get();
-            if ptr.is_null() {
-                Some(self.init())
-            } else if ptr == done() {
-                None
-            } else {
-                Some((*ptr).clone())
-            }
+impl<T: Send + Sync + 'static> Lazy<T> {
+    /// Safety: `init` must not call `get` on the variable that is being
+    /// initialized.
+    pub unsafe fn get(&'static self, init: fn() -> Arc<T>) -> Option<Arc<T>> {
+        let _guard = self.lock.lock();
+        let ptr = self.ptr.get();
+        if ptr.is_null() {
+            Some(self.init(init))
+        } else if ptr == done() {
+            None
+        } else {
+            Some((*ptr).clone())
         }
     }
 
     // Must only be called with `lock` held
-    unsafe fn init(&'static self) -> Arc<T> {
+    unsafe fn init(&'static self, init: fn() -> Arc<T>) -> Arc<T> {
         // If we successfully register an at exit handler, then we cache the
         // `Arc` allocation in our own internal box (it will get deallocated by
         // the at exit handler). Otherwise we just return the freshly allocated
@@ -66,8 +64,8 @@ unsafe fn init(&'static self) -> Arc<T> {
         });
         // This could reentrantly call `init` again, which is a problem
         // because our `lock` allows reentrancy!
-        // That's why `new` is unsafe and requires the caller to ensure no reentrancy happens.
-        let ret = (self.init)();
+        // That's why `get` is unsafe and requires the caller to ensure no reentrancy happens.
+        let ret = init();
         if registered.is_ok() {
             self.ptr.set(Box::into_raw(Box::new(ret.clone())));
         }
index 1f256f518c7ce083585f57b74ddccbfb95912b04..a413432cdaabc6ba2b0075a2e10e161379ec7578 100644 (file)
@@ -197,9 +197,11 @@ pub struct StdinLock<'a> {
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn stdin() -> Stdin {
-    static INSTANCE: Lazy<Mutex<BufReader<Maybe<StdinRaw>>>> = unsafe { Lazy::new(stdin_init) };
+    static INSTANCE: Lazy<Mutex<BufReader<Maybe<StdinRaw>>>> = Lazy::new();
     return Stdin {
-        inner: INSTANCE.get().expect("cannot access stdin during shutdown"),
+        inner: unsafe {
+            INSTANCE.get(stdin_init).expect("cannot access stdin during shutdown")
+        },
     };
 
     fn stdin_init() -> Arc<Mutex<BufReader<Maybe<StdinRaw>>>> {
@@ -396,10 +398,11 @@ pub struct StdoutLock<'a> {
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn stdout() -> Stdout {
-    static INSTANCE: Lazy<ReentrantMutex<RefCell<LineWriter<Maybe<StdoutRaw>>>>>
-        = unsafe { Lazy::new(stdout_init) };
+    static INSTANCE: Lazy<ReentrantMutex<RefCell<LineWriter<Maybe<StdoutRaw>>>>> = Lazy::new();
     return Stdout {
-        inner: INSTANCE.get().expect("cannot access stdout during shutdown"),
+        inner: unsafe {
+            INSTANCE.get(stdout_init).expect("cannot access stdout during shutdown")
+        },
     };
 
     fn stdout_init() -> Arc<ReentrantMutex<RefCell<LineWriter<Maybe<StdoutRaw>>>>> {
@@ -533,10 +536,11 @@ pub struct StderrLock<'a> {
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn stderr() -> Stderr {
-    static INSTANCE: Lazy<ReentrantMutex<RefCell<Maybe<StderrRaw>>>> =
-        unsafe { Lazy::new(stderr_init) };
+    static INSTANCE: Lazy<ReentrantMutex<RefCell<Maybe<StderrRaw>>>> = Lazy::new();
     return Stderr {
-        inner: INSTANCE.get().expect("cannot access stderr during shutdown"),
+        inner: unsafe {
+            INSTANCE.get(stderr_init).expect("cannot access stderr during shutdown")
+        },
     };
 
     fn stderr_init() -> Arc<ReentrantMutex<RefCell<Maybe<StderrRaw>>>> {
index ecd52a62eab2692601254ed5d9b17ce30593b293..3eecdf14a4e50029eb62d7a161e310bcbd71f905 100644 (file)
@@ -107,7 +107,11 @@ pub struct Stability {
     pub level: StabilityLevel,
     pub feature: Symbol,
     pub rustc_depr: Option<RustcDeprecation>,
-    pub rustc_const_unstable: Option<RustcConstUnstable>,
+    /// `None` means the function is stable but needs to be allowed by the
+    /// `min_const_fn` feature
+    /// `Some` contains the feature gate required to be able to use the function
+    /// as const fn
+    pub const_stability: Option<Symbol>,
 }
 
 /// The available stability levels.
@@ -141,11 +145,6 @@ pub struct RustcDeprecation {
     pub reason: Symbol,
 }
 
-#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Eq, Hash)]
-pub struct RustcConstUnstable {
-    pub feature: Symbol,
-}
-
 /// Check if `attrs` contains an attribute like `#![feature(feature_name)]`.
 /// This will not perform any "sanity checks" on the form of the attributes.
 pub fn contains_feature_attr(attrs: &[Attribute], feature_name: &str) -> bool {
@@ -176,7 +175,7 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler,
 
     let mut stab: Option<Stability> = None;
     let mut rustc_depr: Option<RustcDeprecation> = None;
-    let mut rustc_const_unstable: Option<RustcConstUnstable> = None;
+    let mut rustc_const_unstable: Option<Symbol> = None;
 
     'outer: for attr in attrs_iter {
         if ![
@@ -191,6 +190,7 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler,
         mark_used(attr);
 
         let meta = attr.meta();
+        // attributes with data
         if let Some(MetaItem { node: MetaItemKind::List(ref metas), .. }) = meta {
             let meta = meta.as_ref().unwrap();
             let get = |meta: &MetaItem, item: &mut Option<Symbol>| {
@@ -272,9 +272,7 @@ macro_rules! get_meta {
 
                     get_meta!(feature);
                     if let Some(feature) = feature {
-                        rustc_const_unstable = Some(RustcConstUnstable {
-                            feature
-                        });
+                        rustc_const_unstable = Some(feature);
                     } else {
                         span_err!(diagnostic, attr.span(), E0629, "missing 'feature'");
                         continue
@@ -330,7 +328,7 @@ macro_rules! get_meta {
                                 },
                                 feature,
                                 rustc_depr: None,
-                                rustc_const_unstable: None,
+                                const_stability: None,
                             })
                         }
                         (None, _, _) => {
@@ -379,7 +377,7 @@ macro_rules! get_meta {
                                 },
                                 feature,
                                 rustc_depr: None,
-                                rustc_const_unstable: None,
+                                const_stability: None,
                             })
                         }
                         (None, _) => {
@@ -412,9 +410,9 @@ macro_rules! get_meta {
     }
 
     // Merge the const-unstable info into the stability info
-    if let Some(rustc_const_unstable) = rustc_const_unstable {
+    if let Some(feature) = rustc_const_unstable {
         if let Some(ref mut stab) = stab {
-            stab.rustc_const_unstable = Some(rustc_const_unstable);
+            stab.const_stability = Some(feature);
         } else {
             span_err!(diagnostic, item_sp, E0630,
                       "rustc_const_unstable attribute must be paired with \
index cd9d76822106c431cd07254805310e7e8b1e1227..19bbbceff5fc02f3d6ef9d8e5f7d8421efc3b0f5 100644 (file)
@@ -15,7 +15,7 @@
 pub use self::builtin::{
     cfg_matches, contains_feature_attr, eval_condition, find_crate_name, find_deprecation,
     find_repr_attrs, find_stability, find_unwind_attr, Deprecation, InlineAttr, IntType, ReprAttr,
-    RustcConstUnstable, RustcDeprecation, Stability, StabilityLevel, UnwindAttr,
+    RustcDeprecation, Stability, StabilityLevel, UnwindAttr,
 };
 pub use self::IntType::*;
 pub use self::ReprAttr::*;
index 080860f17f5ddf5226ffe83c9d0cb55911746b26..f226c9dd979d44d0fcbcdfa505aac85b698cabe5 100644 (file)
 use std::{env, path};
 
 macro_rules! set {
+    // The const_fn feature also enables the min_const_fn feature, because `min_const_fn` allows
+    // the declaration `const fn`, but the `const_fn` feature gate enables things inside those
+    // functions that we do not want to expose to the user for now.
+    (const_fn) => {{
+        fn f(features: &mut Features, _: Span) {
+            features.const_fn = true;
+            features.min_const_fn = true;
+        }
+        f as fn(&mut Features, Span)
+    }};
     ($field: ident) => {{
         fn f(features: &mut Features, _: Span) {
             features.$field = true;
@@ -206,25 +216,28 @@ pub fn walk_feature_fields<F>(&self, mut f: F)
     // #23121. Array patterns have some hazards yet.
     (active, slice_patterns, "1.0.0", Some(23121), None),
 
-    // Allows the definition of `const fn` functions.
+    // Allows the definition of `const fn` functions with some advanced features.
     (active, const_fn, "1.2.0", Some(24111), None),
 
+    // Allows the definition of `const fn` functions.
+    (active, min_const_fn, "1.30.0", Some(53555), None),
+
     // Allows let bindings and destructuring in `const fn` functions and constants.
     (active, const_let, "1.22.1", Some(48821), None),
 
-    // Allows accessing fields of unions inside const fn
+    // Allows accessing fields of unions inside const fn.
     (active, const_fn_union, "1.27.0", Some(51909), None),
 
-    // Allows casting raw pointers to `usize` during const eval
+    // Allows casting raw pointers to `usize` during const eval.
     (active, const_raw_ptr_to_usize_cast, "1.27.0", Some(51910), None),
 
-    // Allows dereferencing raw pointers during const eval
+    // Allows dereferencing raw pointers during const eval.
     (active, const_raw_ptr_deref, "1.27.0", Some(51911), None),
 
-    // Allows reinterpretation of the bits of a value of one type as another type during const eval
+    // Allows reinterpretation of the bits of a value of one type as another type during const eval.
     (active, const_transmute, "1.29.0", Some(53605), None),
 
-    // Allows comparing raw pointers during const eval
+    // Allows comparing raw pointers during const eval.
     (active, const_compare_raw_pointers, "1.27.0", Some(53020), None),
 
     // Allows panicking during const eval (produces compile-time errors)
@@ -1786,7 +1799,7 @@ fn visit_fn(&mut self,
                     gate_feature_post!(&self, async_await, span, "async fn is unstable");
                 }
                 if header.constness.node == ast::Constness::Const {
-                    gate_feature_post!(&self, const_fn, span, "const fn is unstable");
+                    gate_feature_post!(&self, min_const_fn, span, "const fn is unstable");
                 }
                 // stability of const fn methods are covered in
                 // visit_trait_item and visit_impl_item below; this is
@@ -1844,7 +1857,7 @@ fn visit_impl_item(&mut self, ii: &'a ast::ImplItem) {
         match ii.node {
             ast::ImplItemKind::Method(ref sig, _) => {
                 if sig.header.constness.node == ast::Constness::Const {
-                    gate_feature_post!(&self, const_fn, ii.span, "const fn is unstable");
+                    gate_feature_post!(&self, min_const_fn, ii.span, "const fn is unstable");
                 }
             }
             ast::ImplItemKind::Existential(..) => {
index b4b54e13a698ee87d2334ca6a3eae888e1b48ab6..72c0e33cd9ecf46e636b7d3e5f3f971c7dd17d3d 100644 (file)
@@ -10,7 +10,7 @@
 
 // ignore-emscripten
 
-// compile-flags: -Z lower_128bit_ops=yes -C debug_assertions=no
+// compile-flags: -Z lower_128bit_ops=yes -C debug_assertions=no -O
 
 #![feature(const_fn)]
 
@@ -63,103 +63,65 @@ fn main() {
 // END RUST SOURCE
 
 // START rustc.const_signed.Lower128Bit.after.mir
-//     _8 = _1;
-//     _9 = const compiler_builtins::int::addsub::rust_i128_addo(move _8, const 1i128) -> bb10;
-//     ...
-//     _7 = move (_9.0: i128);
-//     ...
-//     _10 = const compiler_builtins::int::addsub::rust_i128_subo(move _7, const 2i128) -> bb11;
-//     ...
-//     _6 = move (_10.0: i128);
-//     ...
-//     _11 = const compiler_builtins::int::mul::rust_i128_mulo(move _6, const 3i128) -> bb12;
-//     ...
-//     _5 = move (_11.0: i128);
-//     ...
-//     _12 = Eq(const 4i128, const 0i128);
-//     assert(!move _12, "attempt to divide by zero") -> bb4;
-//     ...
-//     _13 = Eq(const 4i128, const -1i128);
-//     _14 = Eq(_5, const -170141183460469231731687303715884105728i128);
-//     _15 = BitAnd(move _13, move _14);
-//     assert(!move _15, "attempt to divide with overflow") -> bb5;
-//     ...
-//     _4 = const compiler_builtins::int::sdiv::rust_i128_div(move _5, const 4i128) -> bb13;
-//     ...
-//     _17 = Eq(const 5i128, const -1i128);
-//     _18 = Eq(_4, const -170141183460469231731687303715884105728i128);
-//     _19 = BitAnd(move _17, move _18);
-//     assert(!move _19, "attempt to calculate the remainder with overflow") -> bb7;
-//     ...
-//     _3 = const compiler_builtins::int::sdiv::rust_i128_rem(move _4, const 5i128) -> bb15;
-//     ...
-//     _2 = move (_20.0: i128);
-//     ...
-//     _23 = const 7i32 as u128 (Misc);
-//     _21 = const compiler_builtins::int::shift::rust_i128_shro(move _2, move _23) -> bb16;
-//     ...
-//     _0 = move (_21.0: i128);
-//     ...
-//     assert(!move (_9.1: bool), "attempt to add with overflow") -> bb1;
-//     ...
-//     assert(!move (_10.1: bool), "attempt to subtract with overflow") -> bb2;
-//     ...
-//     assert(!move (_11.1: bool), "attempt to multiply with overflow") -> bb3;
-//     ...
-//     _16 = Eq(const 5i128, const 0i128);
-//     assert(!move _16, "attempt to calculate the remainder with a divisor of zero") -> bb6;
-//     ...
-//     assert(!move (_20.1: bool), "attempt to shift left with overflow") -> bb8;
-//     ...
-//     _22 = const 6i32 as u128 (Misc);
-//     _20 = const compiler_builtins::int::shift::rust_i128_shlo(move _3, move _22) -> bb14;
-//     ...
-//     assert(!move (_21.1: bool), "attempt to shift right with overflow") -> bb9;
+// _7 = const compiler_builtins::int::addsub::rust_i128_add(move _8, const 1i128) -> bb7;
+// ...
+// _10 = Eq(const 4i128, const -1i128);
+// _11 = Eq(_5, const -170141183460469231731687303715884105728i128);
+// _12 = BitAnd(move _10, move _11);
+// assert(!move _12, "attempt to divide with overflow") -> bb2;
+// ...
+// _4 = const compiler_builtins::int::sdiv::rust_i128_div(move _5, const 4i128) -> bb8;
+// ...
+// _14 = Eq(const 5i128, const -1i128);
+// _15 = Eq(_4, const -170141183460469231731687303715884105728i128);
+// _16 = BitAnd(move _14, move _15);
+// assert(!move _16, "attempt to calculate the remainder with overflow") -> bb4;
+// ...
+// _3 = const compiler_builtins::int::sdiv::rust_i128_rem(move _4, const 5i128) -> bb11;
+// ...
+// _9 = Eq(const 4i128, const 0i128);
+// assert(!move _9, "attempt to divide by zero") -> bb1;
+// ...
+// _5 = const compiler_builtins::int::mul::rust_i128_mul(move _6, const 3i128) -> bb5;
+// ...
+// _6 = const compiler_builtins::int::addsub::rust_i128_sub(move _7, const 2i128) -> bb6;
+// ...
+// _13 = Eq(const 5i128, const 0i128);
+// assert(!move _13, "attempt to calculate the remainder with a divisor of zero") -> bb3;
+// ...
+// _17 = const 7i32 as u32 (Misc);
+// _0 = const compiler_builtins::int::shift::rust_i128_shr(move _2, move _17) -> bb9;
+// ...
+// _18 = const 6i32 as u32 (Misc);
+// _2 = const compiler_builtins::int::shift::rust_i128_shl(move _3, move _18) -> bb10;
 // END rustc.const_signed.Lower128Bit.after.mir
 
 // START rustc.const_unsigned.Lower128Bit.after.mir
-//     _8 = _1;
-//     _9 = const compiler_builtins::int::addsub::rust_u128_addo(move _8, const 1u128) -> bb8;
-//     ...
-//     _7 = move (_9.0: u128);
-//     ...
-//     _10 = const compiler_builtins::int::addsub::rust_u128_subo(move _7, const 2u128) -> bb9;
-//     ...
-//     _6 = move (_10.0: u128);
-//     ...
-//     _11 = const compiler_builtins::int::mul::rust_u128_mulo(move _6, const 3u128) -> bb10;
-//     ...
-//     _5 = move (_11.0: u128);
-//     ...
-//     _12 = Eq(const 4u128, const 0u128);
-//     assert(!move _12, "attempt to divide by zero") -> bb4;
-//     ...
-//     _4 = const compiler_builtins::int::udiv::rust_u128_div(move _5, const 4u128) -> bb11;
-//     ...
-//     _3 = const compiler_builtins::int::udiv::rust_u128_rem(move _4, const 5u128) -> bb13;
-//     ...
-//     _2 = move (_14.0: u128);
-//     ...
-//     _17 = const 7i32 as u128 (Misc);
-//     _15 = const compiler_builtins::int::shift::rust_u128_shro(move _2, move _17) -> bb14;
-//     ...
-//     _0 = move (_15.0: u128);
-//     ...
-//     assert(!move (_9.1: bool), "attempt to add with overflow") -> bb1;
-//     ...
-//     assert(!move (_10.1: bool), "attempt to subtract with overflow") -> bb2;
-//     ...
-//     assert(!move (_11.1: bool), "attempt to multiply with overflow") -> bb3;
-//     ...
-//     _13 = Eq(const 5u128, const 0u128);
-//     assert(!move _13, "attempt to calculate the remainder with a divisor of zero") -> bb5;
-//     ...
-//     assert(!move (_14.1: bool), "attempt to shift left with overflow") -> bb6;
-//     ...
-//     _16 = const 6i32 as u128 (Misc);
-//     _14 = const compiler_builtins::int::shift::rust_u128_shlo(move _3, move _16) -> bb12;
-//     ...
-//     assert(!move (_15.1: bool), "attempt to shift right with overflow") -> bb7;
+// _8 = _1;
+// _7 = const compiler_builtins::int::addsub::rust_u128_add(move _8, const 1u128) -> bb5;
+// ...
+// _4 = const compiler_builtins::int::udiv::rust_u128_div(move _5, const 4u128) -> bb6;
+// ...
+// _3 = const compiler_builtins::int::udiv::rust_u128_rem(move _4, const 5u128) -> bb9;
+// ...
+// _9 = Eq(const 4u128, const 0u128);
+// assert(!move _9, "attempt to divide by zero") -> bb1;
+// ...
+// _5 = const compiler_builtins::int::mul::rust_u128_mul(move _6, const 3u128) -> bb3;
+// ...
+// _6 = const compiler_builtins::int::addsub::rust_u128_sub(move _7, const 2u128) -> bb4;
+// ...
+// _10 = Eq(const 5u128, const 0u128);
+// assert(!move _10, "attempt to calculate the remainder with a divisor of zero") -> bb2;
+// ...
+// return;
+// ...
+// _11 = const 7i32 as u32 (Misc);
+// _0 = const compiler_builtins::int::shift::rust_u128_shr(move _2, move _11) -> bb7;
+// ...
+// _12 = const 6i32 as u32 (Misc);
+// _2 = const compiler_builtins::int::shift::rust_u128_shl(move _3, move _12) -> bb8;
+
 // END rustc.const_unsigned.Lower128Bit.after.mir
 
 // START rustc.test_signed.Lower128Bit.after.mir
index 53cb4c4b009e5c870c43f9e13ee76fc30f3dc58c..a18d82fb7a4e7e22c334fe85204ff5b500795ae7 100644 (file)
@@ -11,6 +11,8 @@
 // ignore-wasm32
 // ignore-emscripten
 
+// compile-flags: -C debug_assertions=yes
+
 #![feature(const_fn, libc)]
 #![allow(const_err)]
 
@@ -19,7 +21,7 @@
 use std::env;
 use std::process::{Command, Stdio};
 
-// this will panic in debug mode
+// this will panic in debug mode and overflow in release mode
 const fn bar() -> usize { 0 - 1 }
 
 fn foo() {
index 16d87f7e31c9bb126b81f7ac4a0580d9fc1ef2c6..ab8b5792e681d58bb7e6c9af3193f77664c00252 100644 (file)
@@ -4,14 +4,14 @@ note: ...which requires normalizing `ParamEnvAnd { param_env: ParamEnv { caller_
 note: ...which requires const-evaluating `Foo::bytes::{{constant}}`...
   --> $SRC_DIR/libcore/mem.rs:LL:COL
    |
-LL |     unsafe { intrinsics::size_of::<T>() }
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     intrinsics::size_of::<T>()
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: ...which again requires computing layout of `Foo`, completing the cycle
 note: cycle used when const-evaluating `Foo::bytes::{{constant}}`
   --> $SRC_DIR/libcore/mem.rs:LL:COL
    |
-LL |     unsafe { intrinsics::size_of::<T>() }
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     intrinsics::size_of::<T>()
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.nll.stderr b/src/test/ui/consts/min_const_fn/min_const_fn.nll.stderr
new file mode 100644 (file)
index 0000000..b156e5a
--- /dev/null
@@ -0,0 +1,224 @@
+error[E0493]: destructors cannot be evaluated at compile-time
+  --> $DIR/min_const_fn.rs:49:25
+   |
+LL |     const fn into_inner(self) -> T { self.0 } //~ destructors cannot be evaluated
+   |                         ^^^^ constant functions cannot evaluate destructors
+
+error: mutable references in const fn are unstable
+  --> $DIR/min_const_fn.rs:51:5
+   |
+LL |     const fn get_mut(&mut self) -> &mut T { &mut self.0 }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0493]: destructors cannot be evaluated at compile-time
+  --> $DIR/min_const_fn.rs:56:28
+   |
+LL |     const fn into_inner_lt(self) -> T { self.0 } //~ destructors cannot be evaluated
+   |                            ^^^^ constant functions cannot evaluate destructors
+
+error: mutable references in const fn are unstable
+  --> $DIR/min_const_fn.rs:58:5
+   |
+LL |     const fn get_mut_lt(&'a mut self) -> &mut T { &mut self.0 }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0493]: destructors cannot be evaluated at compile-time
+  --> $DIR/min_const_fn.rs:63:27
+   |
+LL |     const fn into_inner_s(self) -> T { self.0 } //~ ERROR destructors
+   |                           ^^^^ constant functions cannot evaluate destructors
+
+error: mutable references in const fn are unstable
+  --> $DIR/min_const_fn.rs:65:5
+   |
+LL |     const fn get_mut_s(&mut self) -> &mut T { &mut self.0 }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: mutable references in const fn are unstable
+  --> $DIR/min_const_fn.rs:70:5
+   |
+LL |     const fn get_mut_sq(&mut self) -> &mut T { &mut self.0 }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: trait bounds other than `Sized` on const fn parameters are unstable
+  --> $DIR/min_const_fn.rs:88:16
+   |
+LL | const fn foo11<T: std::fmt::Display>(t: T) -> T { t }
+   |                ^
+
+error: trait bounds other than `Sized` on const fn parameters are unstable
+  --> $DIR/min_const_fn.rs:90:18
+   |
+LL | const fn foo11_2<T: Send>(t: T) -> T { t }
+   |                  ^
+
+error: only int, `bool` and `char` operations are stable in const fn
+  --> $DIR/min_const_fn.rs:92:33
+   |
+LL | const fn foo19(f: f32) -> f32 { f * 2.0 }
+   |                                 ^^^^^^^
+
+error: only int, `bool` and `char` operations are stable in const fn
+  --> $DIR/min_const_fn.rs:94:35
+   |
+LL | const fn foo19_2(f: f32) -> f32 { 2.0 - f }
+   |                                   ^^^^^^^
+
+error: only int and `bool` operations are stable in const fn
+  --> $DIR/min_const_fn.rs:96:35
+   |
+LL | const fn foo19_3(f: f32) -> f32 { -f }
+   |                                   ^^
+
+error: only int, `bool` and `char` operations are stable in const fn
+  --> $DIR/min_const_fn.rs:98:43
+   |
+LL | const fn foo19_4(f: f32, g: f32) -> f32 { f / g }
+   |                                           ^^^^^
+
+error: cannot access `static` items in const fn
+  --> $DIR/min_const_fn.rs:102:27
+   |
+LL | const fn foo25() -> u32 { BAR } //~ ERROR cannot access `static` items in const fn
+   |                           ^^^
+
+error: cannot access `static` items in const fn
+  --> $DIR/min_const_fn.rs:103:36
+   |
+LL | const fn foo26() -> &'static u32 { &BAR } //~ ERROR cannot access `static` items
+   |                                    ^^^^
+
+error: casting pointers to ints is unstable in const fn
+  --> $DIR/min_const_fn.rs:104:42
+   |
+LL | const fn foo30(x: *const u32) -> usize { x as usize }
+   |                                          ^^^^^^^^^^
+
+error: casting pointers to ints is unstable in const fn
+  --> $DIR/min_const_fn.rs:106:42
+   |
+LL | const fn foo30_2(x: *mut u32) -> usize { x as usize }
+   |                                          ^^^^^^^^^^
+
+error: `if`, `match`, `&&` and `||` are not stable in const fn
+  --> $DIR/min_const_fn.rs:108:38
+   |
+LL | const fn foo30_4(b: bool) -> usize { if b { 1 } else { 42 } }
+   |                                      ^^^^^^^^^^^^^^^^^^^^^^
+
+error: `if`, `match`, `&&` and `||` are not stable in const fn
+  --> $DIR/min_const_fn.rs:110:29
+   |
+LL | const fn foo30_5(b: bool) { while b { } } //~ ERROR not stable in const fn
+   |                             ^^^^^^^^^^^
+
+error: local variables in const fn are unstable
+  --> $DIR/min_const_fn.rs:111:34
+   |
+LL | const fn foo30_6() -> bool { let x = true; x } //~ ERROR local variables in const fn are unstable
+   |                                  ^
+
+error: `if`, `match`, `&&` and `||` are not stable in const fn
+  --> $DIR/min_const_fn.rs:112:44
+   |
+LL | const fn foo36(a: bool, b: bool) -> bool { a && b }
+   |                                            ^^^^^^
+
+error: `if`, `match`, `&&` and `||` are not stable in const fn
+  --> $DIR/min_const_fn.rs:114:44
+   |
+LL | const fn foo37(a: bool, b: bool) -> bool { a || b }
+   |                                            ^^^^^^
+
+error: mutable references in const fn are unstable
+  --> $DIR/min_const_fn.rs:116:14
+   |
+LL | const fn inc(x: &mut i32) { *x += 1 }
+   |              ^
+
+error: trait bounds other than `Sized` on const fn parameters are unstable
+  --> $DIR/min_const_fn.rs:121:6
+   |
+LL | impl<T: std::fmt::Debug> Foo<T> {
+   |      ^
+
+error: trait bounds other than `Sized` on const fn parameters are unstable
+  --> $DIR/min_const_fn.rs:126:6
+   |
+LL | impl<T: std::fmt::Debug + Sized> Foo<T> {
+   |      ^
+
+error: trait bounds other than `Sized` on const fn parameters are unstable
+  --> $DIR/min_const_fn.rs:131:6
+   |
+LL | impl<T: Sync + Sized> Foo<T> {
+   |      ^
+
+error: `impl Trait` in const fn is unstable
+  --> $DIR/min_const_fn.rs:137:1
+   |
+LL | const fn no_rpit2() -> AlanTuring<impl std::fmt::Debug> { AlanTuring(0) }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: trait bounds other than `Sized` on const fn parameters are unstable
+  --> $DIR/min_const_fn.rs:139:34
+   |
+LL | const fn no_apit2(_x: AlanTuring<impl std::fmt::Debug>) {}
+   |                                  ^^^^^^^^^^^^^^^^^^^^
+
+error: trait bounds other than `Sized` on const fn parameters are unstable
+  --> $DIR/min_const_fn.rs:141:22
+   |
+LL | const fn no_apit(_x: impl std::fmt::Debug) {} //~ ERROR trait bounds other than `Sized`
+   |                      ^^^^^^^^^^^^^^^^^^^^
+
+error: `impl Trait` in const fn is unstable
+  --> $DIR/min_const_fn.rs:142:1
+   |
+LL | const fn no_rpit() -> impl std::fmt::Debug {} //~ ERROR `impl Trait` in const fn is unstable
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: trait bounds other than `Sized` on const fn parameters are unstable
+  --> $DIR/min_const_fn.rs:143:23
+   |
+LL | const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {} //~ ERROR trait bounds other than `Sized`
+   |                       ^^
+
+error: trait bounds other than `Sized` on const fn parameters are unstable
+  --> $DIR/min_const_fn.rs:144:1
+   |
+LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0597]: borrowed value does not live long enough
+  --> $DIR/min_const_fn.rs:144:64
+   |
+LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
+   |                                                                ^^ - temporary value only lives until here
+   |                                                                |
+   |                                                                temporary value does not live long enough
+   |
+   = note: borrowed value must be valid for the static lifetime...
+
+error: trait bounds other than `Sized` on const fn parameters are unstable
+  --> $DIR/min_const_fn.rs:149:41
+   |
+LL | const fn really_no_traits_i_mean_it() { (&() as &std::fmt::Debug, ()).1 }
+   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: function pointers in const fn are unstable
+  --> $DIR/min_const_fn.rs:152:21
+   |
+LL | const fn no_fn_ptrs(_x: fn()) {}
+   |                     ^^
+
+error: function pointers in const fn are unstable
+  --> $DIR/min_const_fn.rs:154:1
+   |
+LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 36 previous errors
+
+Some errors occurred: E0493, E0597.
+For more information about an error, try `rustc --explain E0493`.
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.rs b/src/test/ui/consts/min_const_fn/min_const_fn.rs
new file mode 100644 (file)
index 0000000..b861e31
--- /dev/null
@@ -0,0 +1,156 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+#![feature(min_const_fn)]
+
+// ok
+const fn foo1() {}
+const fn foo2(x: i32) -> i32 { x }
+const fn foo3<T>(x: T) -> T { x }
+const fn foo7() {
+    (
+        foo1(),
+        foo2(420),
+        foo3(69),
+    ).0
+}
+const fn foo12<T: Sized>(t: T) -> T { t }
+const fn foo13<T: ?Sized>(t: &T) -> &T { t }
+const fn foo14<'a, T: 'a>(t: &'a T) -> &'a T { t }
+const fn foo15<T>(t: T) -> T where T: Sized { t }
+const fn foo15_2<T>(t: &T) -> &T where T: ?Sized { t }
+const fn foo16(f: f32) -> f32 { f }
+const fn foo17(f: f32) -> u32 { f as u32 }
+const fn foo18(i: i32) -> i32 { i * 3 }
+const fn foo20(b: bool) -> bool { !b }
+const fn foo21<T, U>(t: T, u: U) -> (T, U) { (t, u) }
+const fn foo22(s: &[u8], i: usize) -> u8 { s[i] }
+const FOO: u32 = 42;
+const fn foo23() -> u32 { FOO }
+const fn foo24() -> &'static u32 { &FOO }
+const fn foo27(x: &u32) -> u32 { *x }
+const fn foo28(x: u32) -> u32 { *&x }
+const fn foo29(x: u32) -> i32 { x as i32 }
+const fn foo31(a: bool, b: bool) -> bool { a & b }
+const fn foo32(a: bool, b: bool) -> bool { a | b }
+const fn foo33(a: bool, b: bool) -> bool { a & b }
+const fn foo34(a: bool, b: bool) -> bool { a | b }
+const fn foo35(a: bool, b: bool) -> bool { a ^ b }
+struct Foo<T: ?Sized>(T);
+impl<T> Foo<T> {
+    const fn new(t: T) -> Self { Foo(t) }
+    const fn into_inner(self) -> T { self.0 } //~ destructors cannot be evaluated
+    const fn get(&self) -> &T { &self.0 }
+    const fn get_mut(&mut self) -> &mut T { &mut self.0 }
+    //~^ mutable references in const fn are unstable
+}
+impl<'a, T> Foo<T> {
+    const fn new_lt(t: T) -> Self { Foo(t) }
+    const fn into_inner_lt(self) -> T { self.0 } //~ destructors cannot be evaluated
+    const fn get_lt(&'a self) -> &T { &self.0 }
+    const fn get_mut_lt(&'a mut self) -> &mut T { &mut self.0 }
+    //~^ mutable references in const fn are unstable
+}
+impl<T: Sized> Foo<T> {
+    const fn new_s(t: T) -> Self { Foo(t) }
+    const fn into_inner_s(self) -> T { self.0 } //~ ERROR destructors
+    const fn get_s(&self) -> &T { &self.0 }
+    const fn get_mut_s(&mut self) -> &mut T { &mut self.0 }
+    //~^ mutable references in const fn are unstable
+}
+impl<T: ?Sized> Foo<T> {
+    const fn get_sq(&self) -> &T { &self.0 }
+    const fn get_mut_sq(&mut self) -> &mut T { &mut self.0 }
+    //~^ mutable references in const fn are unstable
+}
+
+
+const fn char_ops(c: char, d: char) -> bool { c == d }
+const fn char_ops2(c: char, d: char) -> bool { c < d }
+const fn char_ops3(c: char, d: char) -> bool { c != d }
+const fn i32_ops(c: i32, d: i32) -> bool { c == d }
+const fn i32_ops2(c: i32, d: i32) -> bool { c < d }
+const fn i32_ops3(c: i32, d: i32) -> bool { c != d }
+const fn i32_ops4(c: i32, d: i32) -> i32 { c + d }
+const fn char_cast(u: u8) -> char { u as char }
+const unsafe fn foo4() -> i32 { 42 }
+const unsafe fn foo5<T>() -> *const T { 0 as *const T }
+const unsafe fn foo6<T>() -> *mut T { 0 as *mut T }
+
+// not ok
+const fn foo11<T: std::fmt::Display>(t: T) -> T { t }
+//~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable
+const fn foo11_2<T: Send>(t: T) -> T { t }
+//~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable
+const fn foo19(f: f32) -> f32 { f * 2.0 }
+//~^ ERROR only int, `bool` and `char` operations are stable in const fn
+const fn foo19_2(f: f32) -> f32 { 2.0 - f }
+//~^ ERROR only int, `bool` and `char` operations are stable in const fn
+const fn foo19_3(f: f32) -> f32 { -f }
+//~^ ERROR only int and `bool` operations are stable in const fn
+const fn foo19_4(f: f32, g: f32) -> f32 { f / g }
+//~^ ERROR only int, `bool` and `char` operations are stable in const fn
+
+static BAR: u32 = 42;
+const fn foo25() -> u32 { BAR } //~ ERROR cannot access `static` items in const fn
+const fn foo26() -> &'static u32 { &BAR } //~ ERROR cannot access `static` items
+const fn foo30(x: *const u32) -> usize { x as usize }
+//~^ ERROR casting pointers to int
+const fn foo30_2(x: *mut u32) -> usize { x as usize }
+//~^ ERROR casting pointers to int
+const fn foo30_4(b: bool) -> usize { if b { 1 } else { 42 } }
+//~^ ERROR `if`, `match`, `&&` and `||` are not stable in const fn
+const fn foo30_5(b: bool) { while b { } } //~ ERROR not stable in const fn
+const fn foo30_6() -> bool { let x = true; x } //~ ERROR local variables in const fn are unstable
+const fn foo36(a: bool, b: bool) -> bool { a && b }
+//~^ ERROR `if`, `match`, `&&` and `||` are not stable in const fn
+const fn foo37(a: bool, b: bool) -> bool { a || b }
+//~^ ERROR `if`, `match`, `&&` and `||` are not stable in const fn
+const fn inc(x: &mut i32) { *x += 1 }
+//~^ ERROR mutable references in const fn are unstable
+
+fn main() {}
+
+impl<T: std::fmt::Debug> Foo<T> {
+//~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable
+    const fn foo(&self) {}
+}
+
+impl<T: std::fmt::Debug + Sized> Foo<T> {
+//~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable
+    const fn foo2(&self) {}
+}
+
+impl<T: Sync + Sized> Foo<T> {
+//~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable
+    const fn foo3(&self) {}
+}
+
+struct AlanTuring<T>(T);
+const fn no_rpit2() -> AlanTuring<impl std::fmt::Debug> { AlanTuring(0) }
+//~^ ERROR `impl Trait` in const fn is unstable
+const fn no_apit2(_x: AlanTuring<impl std::fmt::Debug>) {}
+//~^ ERROR trait bounds other than `Sized`
+const fn no_apit(_x: impl std::fmt::Debug) {} //~ ERROR trait bounds other than `Sized`
+const fn no_rpit() -> impl std::fmt::Debug {} //~ ERROR `impl Trait` in const fn is unstable
+const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {} //~ ERROR trait bounds other than `Sized`
+const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
+//~^ ERROR trait bounds other than `Sized`
+
+const fn no_unsafe() { unsafe {} }
+
+const fn really_no_traits_i_mean_it() { (&() as &std::fmt::Debug, ()).1 }
+//~^ ERROR trait bounds other than `Sized`
+
+const fn no_fn_ptrs(_x: fn()) {}
+//~^ ERROR function pointers in const fn are unstable
+const fn no_fn_ptrs2() -> fn() { fn foo() {} foo }
+//~^ ERROR function pointers in const fn are unstable
+
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.stderr b/src/test/ui/consts/min_const_fn/min_const_fn.stderr
new file mode 100644 (file)
index 0000000..019948c
--- /dev/null
@@ -0,0 +1,213 @@
+error[E0493]: destructors cannot be evaluated at compile-time
+  --> $DIR/min_const_fn.rs:49:25
+   |
+LL |     const fn into_inner(self) -> T { self.0 } //~ destructors cannot be evaluated
+   |                         ^^^^ constant functions cannot evaluate destructors
+
+error: mutable references in const fn are unstable
+  --> $DIR/min_const_fn.rs:51:5
+   |
+LL |     const fn get_mut(&mut self) -> &mut T { &mut self.0 }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0493]: destructors cannot be evaluated at compile-time
+  --> $DIR/min_const_fn.rs:56:28
+   |
+LL |     const fn into_inner_lt(self) -> T { self.0 } //~ destructors cannot be evaluated
+   |                            ^^^^ constant functions cannot evaluate destructors
+
+error: mutable references in const fn are unstable
+  --> $DIR/min_const_fn.rs:58:5
+   |
+LL |     const fn get_mut_lt(&'a mut self) -> &mut T { &mut self.0 }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0493]: destructors cannot be evaluated at compile-time
+  --> $DIR/min_const_fn.rs:63:27
+   |
+LL |     const fn into_inner_s(self) -> T { self.0 } //~ ERROR destructors
+   |                           ^^^^ constant functions cannot evaluate destructors
+
+error: mutable references in const fn are unstable
+  --> $DIR/min_const_fn.rs:65:5
+   |
+LL |     const fn get_mut_s(&mut self) -> &mut T { &mut self.0 }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: mutable references in const fn are unstable
+  --> $DIR/min_const_fn.rs:70:5
+   |
+LL |     const fn get_mut_sq(&mut self) -> &mut T { &mut self.0 }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: trait bounds other than `Sized` on const fn parameters are unstable
+  --> $DIR/min_const_fn.rs:88:16
+   |
+LL | const fn foo11<T: std::fmt::Display>(t: T) -> T { t }
+   |                ^
+
+error: trait bounds other than `Sized` on const fn parameters are unstable
+  --> $DIR/min_const_fn.rs:90:18
+   |
+LL | const fn foo11_2<T: Send>(t: T) -> T { t }
+   |                  ^
+
+error: only int, `bool` and `char` operations are stable in const fn
+  --> $DIR/min_const_fn.rs:92:33
+   |
+LL | const fn foo19(f: f32) -> f32 { f * 2.0 }
+   |                                 ^^^^^^^
+
+error: only int, `bool` and `char` operations are stable in const fn
+  --> $DIR/min_const_fn.rs:94:35
+   |
+LL | const fn foo19_2(f: f32) -> f32 { 2.0 - f }
+   |                                   ^^^^^^^
+
+error: only int and `bool` operations are stable in const fn
+  --> $DIR/min_const_fn.rs:96:35
+   |
+LL | const fn foo19_3(f: f32) -> f32 { -f }
+   |                                   ^^
+
+error: only int, `bool` and `char` operations are stable in const fn
+  --> $DIR/min_const_fn.rs:98:43
+   |
+LL | const fn foo19_4(f: f32, g: f32) -> f32 { f / g }
+   |                                           ^^^^^
+
+error: cannot access `static` items in const fn
+  --> $DIR/min_const_fn.rs:102:27
+   |
+LL | const fn foo25() -> u32 { BAR } //~ ERROR cannot access `static` items in const fn
+   |                           ^^^
+
+error: cannot access `static` items in const fn
+  --> $DIR/min_const_fn.rs:103:36
+   |
+LL | const fn foo26() -> &'static u32 { &BAR } //~ ERROR cannot access `static` items
+   |                                    ^^^^
+
+error: casting pointers to ints is unstable in const fn
+  --> $DIR/min_const_fn.rs:104:42
+   |
+LL | const fn foo30(x: *const u32) -> usize { x as usize }
+   |                                          ^^^^^^^^^^
+
+error: casting pointers to ints is unstable in const fn
+  --> $DIR/min_const_fn.rs:106:42
+   |
+LL | const fn foo30_2(x: *mut u32) -> usize { x as usize }
+   |                                          ^^^^^^^^^^
+
+error: `if`, `match`, `&&` and `||` are not stable in const fn
+  --> $DIR/min_const_fn.rs:108:38
+   |
+LL | const fn foo30_4(b: bool) -> usize { if b { 1 } else { 42 } }
+   |                                      ^^^^^^^^^^^^^^^^^^^^^^
+
+error: `if`, `match`, `&&` and `||` are not stable in const fn
+  --> $DIR/min_const_fn.rs:110:29
+   |
+LL | const fn foo30_5(b: bool) { while b { } } //~ ERROR not stable in const fn
+   |                             ^^^^^^^^^^^
+
+error: local variables in const fn are unstable
+  --> $DIR/min_const_fn.rs:111:34
+   |
+LL | const fn foo30_6() -> bool { let x = true; x } //~ ERROR local variables in const fn are unstable
+   |                                  ^
+
+error: `if`, `match`, `&&` and `||` are not stable in const fn
+  --> $DIR/min_const_fn.rs:112:44
+   |
+LL | const fn foo36(a: bool, b: bool) -> bool { a && b }
+   |                                            ^^^^^^
+
+error: `if`, `match`, `&&` and `||` are not stable in const fn
+  --> $DIR/min_const_fn.rs:114:44
+   |
+LL | const fn foo37(a: bool, b: bool) -> bool { a || b }
+   |                                            ^^^^^^
+
+error: mutable references in const fn are unstable
+  --> $DIR/min_const_fn.rs:116:14
+   |
+LL | const fn inc(x: &mut i32) { *x += 1 }
+   |              ^
+
+error: trait bounds other than `Sized` on const fn parameters are unstable
+  --> $DIR/min_const_fn.rs:121:6
+   |
+LL | impl<T: std::fmt::Debug> Foo<T> {
+   |      ^
+
+error: trait bounds other than `Sized` on const fn parameters are unstable
+  --> $DIR/min_const_fn.rs:126:6
+   |
+LL | impl<T: std::fmt::Debug + Sized> Foo<T> {
+   |      ^
+
+error: trait bounds other than `Sized` on const fn parameters are unstable
+  --> $DIR/min_const_fn.rs:131:6
+   |
+LL | impl<T: Sync + Sized> Foo<T> {
+   |      ^
+
+error: `impl Trait` in const fn is unstable
+  --> $DIR/min_const_fn.rs:137:1
+   |
+LL | const fn no_rpit2() -> AlanTuring<impl std::fmt::Debug> { AlanTuring(0) }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: trait bounds other than `Sized` on const fn parameters are unstable
+  --> $DIR/min_const_fn.rs:139:34
+   |
+LL | const fn no_apit2(_x: AlanTuring<impl std::fmt::Debug>) {}
+   |                                  ^^^^^^^^^^^^^^^^^^^^
+
+error: trait bounds other than `Sized` on const fn parameters are unstable
+  --> $DIR/min_const_fn.rs:141:22
+   |
+LL | const fn no_apit(_x: impl std::fmt::Debug) {} //~ ERROR trait bounds other than `Sized`
+   |                      ^^^^^^^^^^^^^^^^^^^^
+
+error: `impl Trait` in const fn is unstable
+  --> $DIR/min_const_fn.rs:142:1
+   |
+LL | const fn no_rpit() -> impl std::fmt::Debug {} //~ ERROR `impl Trait` in const fn is unstable
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: trait bounds other than `Sized` on const fn parameters are unstable
+  --> $DIR/min_const_fn.rs:143:23
+   |
+LL | const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {} //~ ERROR trait bounds other than `Sized`
+   |                       ^^
+
+error: trait bounds other than `Sized` on const fn parameters are unstable
+  --> $DIR/min_const_fn.rs:144:1
+   |
+LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: trait bounds other than `Sized` on const fn parameters are unstable
+  --> $DIR/min_const_fn.rs:149:41
+   |
+LL | const fn really_no_traits_i_mean_it() { (&() as &std::fmt::Debug, ()).1 }
+   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: function pointers in const fn are unstable
+  --> $DIR/min_const_fn.rs:152:21
+   |
+LL | const fn no_fn_ptrs(_x: fn()) {}
+   |                     ^^
+
+error: function pointers in const fn are unstable
+  --> $DIR/min_const_fn.rs:154:1
+   |
+LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 35 previous errors
+
+For more information about this error, try `rustc --explain E0493`.
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.nll.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.nll.stderr
new file mode 100644 (file)
index 0000000..cfcc799
--- /dev/null
@@ -0,0 +1,25 @@
+error: trait bounds other than `Sized` on const fn parameters are unstable
+  --> $DIR/min_const_fn_dyn.rs:21:5
+   |
+LL |     x.0.field;
+   |     ^^^^^^^^^
+
+error: trait bounds other than `Sized` on const fn parameters are unstable
+  --> $DIR/min_const_fn_dyn.rs:24:66
+   |
+LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) }
+   |                                                                  ^^
+
+error[E0597]: borrowed value does not live long enough
+  --> $DIR/min_const_fn_dyn.rs:24:67
+   |
+LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) }
+   |                                                                   ^    - temporary value only lives until here
+   |                                                                   |
+   |                                                                   temporary value does not live long enough
+   |
+   = note: borrowed value must be valid for the static lifetime...
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs
new file mode 100644 (file)
index 0000000..38e2825
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+#![feature(min_const_fn)]
+
+struct HasDyn {
+    field: &'static dyn std::fmt::Debug,
+}
+
+struct Hide(HasDyn);
+
+const fn no_inner_dyn_trait(_x: Hide) {}
+const fn no_inner_dyn_trait2(x: Hide) {
+    x.0.field;
+//~^ ERROR trait bounds other than `Sized`
+}
+const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) }
+//~^ ERROR trait bounds other than `Sized`
+
+fn main() {}
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr
new file mode 100644 (file)
index 0000000..3a1055f
--- /dev/null
@@ -0,0 +1,14 @@
+error: trait bounds other than `Sized` on const fn parameters are unstable
+  --> $DIR/min_const_fn_dyn.rs:21:5
+   |
+LL |     x.0.field;
+   |     ^^^^^^^^^
+
+error: trait bounds other than `Sized` on const fn parameters are unstable
+  --> $DIR/min_const_fn_dyn.rs:24:66
+   |
+LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) }
+   |                                                                  ^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.rs b/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.rs
new file mode 100644 (file)
index 0000000..100d275
--- /dev/null
@@ -0,0 +1,29 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+#![feature(min_const_fn)]
+
+struct HasPtr {
+    field: fn(),
+}
+
+struct Hide(HasPtr);
+
+fn field() {}
+
+const fn no_inner_dyn_trait(_x: Hide) {}
+const fn no_inner_dyn_trait2(x: Hide) {
+    x.0.field;
+//~^ ERROR function pointers in const fn
+}
+const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasPtr { field }) }
+//~^ ERROR function pointers in const fn
+
+fn main() {}
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.stderr
new file mode 100644 (file)
index 0000000..c10af3d
--- /dev/null
@@ -0,0 +1,14 @@
+error: function pointers in const fn are unstable
+  --> $DIR/min_const_fn_fn_ptr.rs:23:5
+   |
+LL |     x.0.field;
+   |     ^^^^^^^^^
+
+error: function pointers in const fn are unstable
+  --> $DIR/min_const_fn_fn_ptr.rs:26:59
+   |
+LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasPtr { field }) }
+   |                                                           ^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs
new file mode 100644 (file)
index 0000000..4ce62ec
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+#![unstable(feature = "humans",
+            reason = "who ever let humans program computers,
+            we're apparently really bad at it",
+            issue = "0")]
+
+#![feature(rustc_const_unstable, const_fn, foo)]
+#![feature(staged_api)]
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature="foo")]
+const fn foo() -> u32 { 42 }
+
+#[stable(feature = "rust1", since = "1.0.0")]
+// can't call non-min_const_fn
+const fn bar() -> u32 { foo() } //~ ERROR can only call other `min_const_fn`
+
+#[unstable(feature = "rust1", issue="0")]
+const fn foo2() -> u32 { 42 }
+
+#[stable(feature = "rust1", since = "1.0.0")]
+// can't call non-min_const_fn
+const fn bar2() -> u32 { foo2() } //~ ERROR can only call other `min_const_fn`
+
+#[stable(feature = "rust1", since = "1.0.0")]
+// conformity is required, even with `const_fn` feature gate
+const fn bar3() -> u32 { (5f32 + 6f32) as u32 } //~ ERROR only int, `bool` and `char` operations
+
+fn main() {}
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr
new file mode 100644 (file)
index 0000000..8e47090
--- /dev/null
@@ -0,0 +1,20 @@
+error: can only call other `min_const_fn` within a `min_const_fn`
+  --> $DIR/min_const_fn_libstd_stability.rs:25:25
+   |
+LL | const fn bar() -> u32 { foo() } //~ ERROR can only call other `min_const_fn`
+   |                         ^^^^^
+
+error: can only call other `min_const_fn` within a `min_const_fn`
+  --> $DIR/min_const_fn_libstd_stability.rs:32:26
+   |
+LL | const fn bar2() -> u32 { foo2() } //~ ERROR can only call other `min_const_fn`
+   |                          ^^^^^^
+
+error: only int, `bool` and `char` operations are stable in const fn
+  --> $DIR/min_const_fn_libstd_stability.rs:36:26
+   |
+LL | const fn bar3() -> u32 { (5f32 + 6f32) as u32 } //~ ERROR only int, `bool` and `char` operations
+   |                          ^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.rs b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.rs
new file mode 100644 (file)
index 0000000..e7caa4c
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+#![feature(min_const_fn)]
+
+// ok
+const unsafe fn foo4() -> i32 { 42 }
+const unsafe fn foo5<T>() -> *const T { 0 as *const T }
+const unsafe fn foo6<T>() -> *mut T { 0 as *mut T }
+const fn no_unsafe() { unsafe {} }
+
+// not ok
+const fn foo8() -> i32 {
+    unsafe { foo4() } //~ ERROR unsafe operations are not allowed in const fn
+}
+const fn foo9() -> *const String {
+    unsafe { foo5::<String>() } //~ ERROR unsafe operations are not allowed in const fn
+}
+const fn foo10() -> *const Vec<std::cell::Cell<u32>> {
+    unsafe { foo6::<Vec<std::cell::Cell<u32>>>() } //~ ERROR not allowed in const fn
+}
+const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn
+//~^ dereferencing raw pointers in constant functions
+
+fn main() {}
+
+const unsafe fn no_union() {
+    union Foo { x: (), y: () }
+    Foo { x: () }.y //~ ERROR not allowed in const fn
+    //~^ unions in const fn
+}
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr
new file mode 100644 (file)
index 0000000..17cba85
--- /dev/null
@@ -0,0 +1,59 @@
+error[E0658]: dereferencing raw pointers in constant functions is unstable (see issue #51911)
+  --> $DIR/min_const_fn_unsafe.rs:29:51
+   |
+LL | const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn
+   |                                                   ^^
+   |
+   = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable
+
+error[E0658]: unions in const fn are unstable (see issue #51909)
+  --> $DIR/min_const_fn_unsafe.rs:36:5
+   |
+LL |     Foo { x: () }.y //~ ERROR not allowed in const fn
+   |     ^^^^^^^^^^^^^^^
+   |
+   = help: add #![feature(const_fn_union)] to the crate attributes to enable
+
+error: call to unsafe function is unsafe and unsafe operations are not allowed in const fn
+  --> $DIR/min_const_fn_unsafe.rs:21:14
+   |
+LL |     unsafe { foo4() } //~ ERROR unsafe operations are not allowed in const fn
+   |              ^^^^^^ call to unsafe function
+   |
+   = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: call to unsafe function is unsafe and unsafe operations are not allowed in const fn
+  --> $DIR/min_const_fn_unsafe.rs:24:14
+   |
+LL |     unsafe { foo5::<String>() } //~ ERROR unsafe operations are not allowed in const fn
+   |              ^^^^^^^^^^^^^^^^ call to unsafe function
+   |
+   = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: call to unsafe function is unsafe and unsafe operations are not allowed in const fn
+  --> $DIR/min_const_fn_unsafe.rs:27:14
+   |
+LL |     unsafe { foo6::<Vec<std::cell::Cell<u32>>>() } //~ ERROR not allowed in const fn
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
+   |
+   = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: dereference of raw pointer is unsafe and unsafe operations are not allowed in const fn
+  --> $DIR/min_const_fn_unsafe.rs:29:51
+   |
+LL | const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn
+   |                                                   ^^ dereference of raw pointer
+   |
+   = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error: access to union field is unsafe and unsafe operations are not allowed in const fn
+  --> $DIR/min_const_fn_unsafe.rs:36:5
+   |
+LL |     Foo { x: () }.y //~ ERROR not allowed in const fn
+   |     ^^^^^^^^^^^^^^^ access to union field
+   |
+   = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
index 490a8e0ff0f1d1cfb0217d59aa67c741df9b0c14..438dd50f2bfa80aaca4ed97b47cf152bed233132 100644 (file)
@@ -4,8 +4,8 @@ error[E0308]: intrinsic has wrong type
 LL |     fn size_of<T>(); //~ ERROR E0308
    |     ^^^^^^^^^^^^^^^^ expected (), found usize
    |
-   = note: expected type `unsafe extern "rust-intrinsic" fn()`
-              found type `unsafe extern "rust-intrinsic" fn() -> usize`
+   = note: expected type `extern "rust-intrinsic" fn()`
+              found type `extern "rust-intrinsic" fn() -> usize`
 
 error: aborting due to previous error
 
index 1d1dedddaaa3e72099f70dab571a40f976d0359e..f774658975b79d983021d8ee80f4c430704a83a2 100644 (file)
@@ -8,9 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// Test use of const fn without feature gate.
+// Test use of const fn without the `const_fn` feature gate.
+// `min_const_fn` is checked in its own file
+#![feature(min_const_fn)]
 
-const fn foo() -> usize { 0 } //~ ERROR const fn is unstable
+const fn foo() -> usize { 0 } // ok
 
 trait Foo {
     const fn foo() -> u32; //~ ERROR const fn is unstable
@@ -20,12 +22,11 @@ const fn bar() -> u32 { 0 } //~ ERROR const fn is unstable
 }
 
 impl Foo {
-    const fn baz() -> u32 { 0 } //~ ERROR const fn is unstable
+    const fn baz() -> u32 { 0 } // ok
 }
 
 impl Foo for u32 {
-    const fn foo() -> u32 { 0 } //~ ERROR const fn is unstable
-                                //~| ERROR trait fns cannot be declared const
+    const fn foo() -> u32 { 0 } //~ ERROR trait fns cannot be declared const
 }
 
 static FOO: usize = foo();
index d7c00a3e0cb40e7f6ca568ac48921d33b4a8dcdd..26c0c7877b4ecc6f51b03b1531e65a720dced564 100644 (file)
@@ -1,31 +1,23 @@
 error[E0379]: trait fns cannot be declared const
-  --> $DIR/feature-gate-const_fn.rs:16:5
+  --> $DIR/feature-gate-const_fn.rs:18:5
    |
 LL |     const fn foo() -> u32; //~ ERROR const fn is unstable
    |     ^^^^^ trait fns cannot be const
 
 error[E0379]: trait fns cannot be declared const
-  --> $DIR/feature-gate-const_fn.rs:18:5
+  --> $DIR/feature-gate-const_fn.rs:20:5
    |
 LL |     const fn bar() -> u32 { 0 } //~ ERROR const fn is unstable
    |     ^^^^^ trait fns cannot be const
 
 error[E0379]: trait fns cannot be declared const
-  --> $DIR/feature-gate-const_fn.rs:27:5
+  --> $DIR/feature-gate-const_fn.rs:29:5
    |
-LL |     const fn foo() -> u32 { 0 } //~ ERROR const fn is unstable
+LL |     const fn foo() -> u32 { 0 } //~ ERROR trait fns cannot be declared const
    |     ^^^^^ trait fns cannot be const
 
 error[E0658]: const fn is unstable (see issue #24111)
-  --> $DIR/feature-gate-const_fn.rs:13:1
-   |
-LL | const fn foo() -> usize { 0 } //~ ERROR const fn is unstable
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: add #![feature(const_fn)] to the crate attributes to enable
-
-error[E0658]: const fn is unstable (see issue #24111)
-  --> $DIR/feature-gate-const_fn.rs:16:5
+  --> $DIR/feature-gate-const_fn.rs:18:5
    |
 LL |     const fn foo() -> u32; //~ ERROR const fn is unstable
    |     ^^^^^^^^^^^^^^^^^^^^^^
@@ -33,30 +25,14 @@ LL |     const fn foo() -> u32; //~ ERROR const fn is unstable
    = help: add #![feature(const_fn)] to the crate attributes to enable
 
 error[E0658]: const fn is unstable (see issue #24111)
-  --> $DIR/feature-gate-const_fn.rs:18:5
+  --> $DIR/feature-gate-const_fn.rs:20:5
    |
 LL |     const fn bar() -> u32 { 0 } //~ ERROR const fn is unstable
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(const_fn)] to the crate attributes to enable
 
-error[E0658]: const fn is unstable (see issue #24111)
-  --> $DIR/feature-gate-const_fn.rs:23:5
-   |
-LL |     const fn baz() -> u32 { 0 } //~ ERROR const fn is unstable
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: add #![feature(const_fn)] to the crate attributes to enable
-
-error[E0658]: const fn is unstable (see issue #24111)
-  --> $DIR/feature-gate-const_fn.rs:27:5
-   |
-LL |     const fn foo() -> u32 { 0 } //~ ERROR const fn is unstable
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: add #![feature(const_fn)] to the crate attributes to enable
-
-error: aborting due to 8 previous errors
+error: aborting due to 5 previous errors
 
 Some errors occurred: E0379, E0658.
 For more information about an error, try `rustc --explain E0379`.
diff --git a/src/test/ui/feature-gates/feature-gate-min_const_fn.rs b/src/test/ui/feature-gates/feature-gate-min_const_fn.rs
new file mode 100644 (file)
index 0000000..e052ba9
--- /dev/null
@@ -0,0 +1,46 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+// Test use of min_const_fn without feature gate.
+
+const fn foo() -> usize { 0 } //~ ERROR const fn is unstable
+
+trait Foo {
+    const fn foo() -> u32; //~ ERROR const fn is unstable
+                           //~| ERROR trait fns cannot be declared const
+    const fn bar() -> u32 { 0 } //~ ERROR const fn is unstable
+                                //~| ERROR trait fns cannot be declared const
+}
+
+impl Foo {
+    const fn baz() -> u32 { 0 } //~ ERROR const fn is unstable
+}
+
+impl Foo for u32 {
+    const fn foo() -> u32 { 0 } //~ ERROR const fn is unstable
+                                //~| ERROR trait fns cannot be declared const
+}
+
+static FOO: usize = foo();
+const BAR: usize = foo();
+
+macro_rules! constant {
+    ($n:ident: $t:ty = $v:expr) => {
+        const $n: $t = $v;
+    }
+}
+
+constant! {
+    BAZ: usize = foo()
+}
+
+fn main() {
+    let x: [usize; foo()] = [];
+}
diff --git a/src/test/ui/feature-gates/feature-gate-min_const_fn.stderr b/src/test/ui/feature-gates/feature-gate-min_const_fn.stderr
new file mode 100644 (file)
index 0000000..aa77503
--- /dev/null
@@ -0,0 +1,62 @@
+error[E0379]: trait fns cannot be declared const
+  --> $DIR/feature-gate-min_const_fn.rs:16:5
+   |
+LL |     const fn foo() -> u32; //~ ERROR const fn is unstable
+   |     ^^^^^ trait fns cannot be const
+
+error[E0379]: trait fns cannot be declared const
+  --> $DIR/feature-gate-min_const_fn.rs:18:5
+   |
+LL |     const fn bar() -> u32 { 0 } //~ ERROR const fn is unstable
+   |     ^^^^^ trait fns cannot be const
+
+error[E0379]: trait fns cannot be declared const
+  --> $DIR/feature-gate-min_const_fn.rs:27:5
+   |
+LL |     const fn foo() -> u32 { 0 } //~ ERROR const fn is unstable
+   |     ^^^^^ trait fns cannot be const
+
+error[E0658]: const fn is unstable (see issue #53555)
+  --> $DIR/feature-gate-min_const_fn.rs:13:1
+   |
+LL | const fn foo() -> usize { 0 } //~ ERROR const fn is unstable
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: add #![feature(min_const_fn)] to the crate attributes to enable
+
+error[E0658]: const fn is unstable (see issue #24111)
+  --> $DIR/feature-gate-min_const_fn.rs:16:5
+   |
+LL |     const fn foo() -> u32; //~ ERROR const fn is unstable
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: add #![feature(const_fn)] to the crate attributes to enable
+
+error[E0658]: const fn is unstable (see issue #24111)
+  --> $DIR/feature-gate-min_const_fn.rs:18:5
+   |
+LL |     const fn bar() -> u32 { 0 } //~ ERROR const fn is unstable
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: add #![feature(const_fn)] to the crate attributes to enable
+
+error[E0658]: const fn is unstable (see issue #53555)
+  --> $DIR/feature-gate-min_const_fn.rs:23:5
+   |
+LL |     const fn baz() -> u32 { 0 } //~ ERROR const fn is unstable
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: add #![feature(min_const_fn)] to the crate attributes to enable
+
+error[E0658]: const fn is unstable (see issue #53555)
+  --> $DIR/feature-gate-min_const_fn.rs:27:5
+   |
+LL |     const fn foo() -> u32 { 0 } //~ ERROR const fn is unstable
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: add #![feature(min_const_fn)] to the crate attributes to enable
+
+error: aborting due to 8 previous errors
+
+Some errors occurred: E0379, E0658.
+For more information about an error, try `rustc --explain E0379`.