From 472ca7159812f8c360697f63454ee7bda1e02570 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 22 Aug 2018 15:56:37 +0200 Subject: [PATCH 1/6] Implement the `min_const_fn` feature gate --- src/libcore/mem.rs | 28 ++ src/librustc/ich/impls_mir.rs | 1 + src/librustc/ich/impls_syntax.rs | 3 +- src/librustc/middle/stability.rs | 2 +- src/librustc/mir/mod.rs | 2 + src/librustc/ty/context.rs | 31 ++ src/librustc_mir/hair/cx/mod.rs | 8 +- src/librustc_mir/transform/check_unsafety.rs | 33 +- src/librustc_mir/transform/mod.rs | 1 + src/librustc_mir/transform/qualify_consts.rs | 20 +- .../transform/qualify_min_const_fn.rs | 378 ++++++++++++++++++ src/librustc_passes/rvalue_promotion.rs | 4 +- src/librustc_typeck/check/intrinsic.rs | 33 +- src/librustc_typeck/collect.rs | 15 +- src/libstd/io/lazy.rs | 38 +- src/libstd/io/stdio.rs | 20 +- src/libsyntax/attr/builtin.rs | 26 +- src/libsyntax/attr/mod.rs | 2 +- src/libsyntax/feature_gate.rs | 29 +- src/test/mir-opt/lower_128bit_test.rs | 152 +++---- src/test/run-pass/invalid_const_promotion.rs | 4 +- src/test/ui/consts/const-size_of-cycle.stderr | 8 +- .../min_const_fn/min_const_fn.nll.stderr | 224 +++++++++++ .../ui/consts/min_const_fn/min_const_fn.rs | 156 ++++++++ .../consts/min_const_fn/min_const_fn.stderr | 213 ++++++++++ .../min_const_fn/min_const_fn_dyn.nll.stderr | 25 ++ .../consts/min_const_fn/min_const_fn_dyn.rs | 27 ++ .../min_const_fn/min_const_fn_dyn.stderr | 14 + .../min_const_fn/min_const_fn_fn_ptr.rs | 29 ++ .../min_const_fn/min_const_fn_fn_ptr.stderr | 14 + .../min_const_fn_libstd_stability.rs | 38 ++ .../min_const_fn_libstd_stability.stderr | 20 + .../min_const_fn/min_const_fn_unsafe.rs | 38 ++ .../min_const_fn/min_const_fn_unsafe.stderr | 59 +++ src/test/ui/error-codes/E0308.stderr | 4 +- .../ui/feature-gates/feature-gate-const_fn.rs | 11 +- .../feature-gate-const_fn.stderr | 38 +- .../feature-gate-min_const_fn.rs | 46 +++ .../feature-gate-min_const_fn.stderr | 62 +++ 39 files changed, 1626 insertions(+), 230 deletions(-) create mode 100644 src/librustc_mir/transform/qualify_min_const_fn.rs create mode 100644 src/test/ui/consts/min_const_fn/min_const_fn.nll.stderr create mode 100644 src/test/ui/consts/min_const_fn/min_const_fn.rs create mode 100644 src/test/ui/consts/min_const_fn/min_const_fn.stderr create mode 100644 src/test/ui/consts/min_const_fn/min_const_fn_dyn.nll.stderr create mode 100644 src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs create mode 100644 src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr create mode 100644 src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.rs create mode 100644 src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.stderr create mode 100644 src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs create mode 100644 src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr create mode 100644 src/test/ui/consts/min_const_fn/min_const_fn_unsafe.rs create mode 100644 src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr create mode 100644 src/test/ui/feature-gates/feature-gate-min_const_fn.rs create mode 100644 src/test/ui/feature-gates/feature-gate-min_const_fn.stderr diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index f2852d98282b7..e00a22bf8b6c3 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -285,6 +285,15 @@ pub fn forget(t: T) { /// [alignment]: ./fn.align_of.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg(not(stage0))] +pub const fn size_of() -> usize { + intrinsics::size_of::() +} + +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +#[cfg(stage0)] +/// Ceci n'est pas la documentation pub const fn size_of() -> usize { unsafe { intrinsics::size_of::() } } @@ -334,6 +343,16 @@ pub fn size_of_val(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() -> usize { + intrinsics::min_align_of::() +} + +#[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() -> usize { unsafe { intrinsics::min_align_of::() } } @@ -376,6 +395,15 @@ pub fn min_align_of_val(val: &T) -> usize { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg(not(stage0))] +pub const fn align_of() -> usize { + intrinsics::min_align_of::() +} + +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +#[cfg(stage0)] +/// Ceci n'est pas la documentation pub const fn align_of() -> usize { unsafe { intrinsics::min_align_of::() } } diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index 1c9387d02d5a3..f11e448796462 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -65,6 +65,7 @@ for mir::UnsafetyViolationKind { 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); diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index ac5fdb2fe2797..a15411c7d8369 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -130,7 +130,7 @@ impl_stable_hash_for!(struct ::syntax::attr::Stability { level, feature, rustc_depr, - rustc_const_unstable + const_stability }); impl<'a> HashStable> @@ -161,7 +161,6 @@ for ::syntax::attr::StabilityLevel { } 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 { diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 85195b0f62e7c..f237c5b397bd5 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -440,7 +440,7 @@ impl<'a, 'tcx> Index<'tcx> { }, feature: Symbol::intern("rustc_private"), rustc_depr: None, - rustc_const_unstable: None, + const_stability: None, }); annotator.parent_stab = Some(stability); } diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 0840f333c876b..0e60d6565176a 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -2394,6 +2394,8 @@ impl Location { #[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), } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index de50598c42c9d..6981d92f05f00 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1099,6 +1099,37 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { 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 diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index c9fd1d04e547b..b4257a40e38af 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -18,7 +18,6 @@ use hair::*; 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 @@ impl<'a, 'gcx, 'tcx> Cx<'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 @@ impl<'a, 'gcx, 'tcx> Cx<'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); diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index f6006ae045ee7..ec7fd371a442b 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -28,6 +28,7 @@ use util; pub struct UnsafetyChecker<'a, 'tcx: 'a> { mir: &'a Mir<'tcx>, + min_const_fn: bool, source_scope_local_data: &'a IndexVec, violations: Vec, 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, - 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, + 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 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { 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 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { 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, diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index 90dfebeef1b0c..1e05b07030ef8 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -36,6 +36,7 @@ pub mod elaborate_drops; 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; diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 36dcd1714716c..c696318d283ce 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -916,9 +916,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { ); } } 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 @@ impl MirPass for QualifyAndPromoteConstants { 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 index 0000000000000..53ba4b03cb734 --- /dev/null +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -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)>; + +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 + ), + } +} diff --git a/src/librustc_passes/rvalue_promotion.rs b/src/librustc_passes/rvalue_promotion.rs index fca1c7f27ab37..f9f74b77e6c46 100644 --- a/src/librustc_passes/rvalue_promotion.rs +++ b/src/librustc_passes/rvalue_promotion.rs @@ -178,9 +178,7 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> { } 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, diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 23872ddf2f64b..c7db3debf5a0d 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -26,12 +26,15 @@ use rustc::hir; use std::iter; -fn equate_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - it: &hir::ForeignItem, - n_tps: usize, - abi: Abi, - inputs: Vec>, - 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>, + 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) } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index a42667ab45fc8..b956c72b3a2da 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -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. diff --git a/src/libstd/io/lazy.rs b/src/libstd/io/lazy.rs index 4fb367fb6ba52..24965ff693184 100644 --- a/src/libstd/io/lazy.rs +++ b/src/libstd/io/lazy.rs @@ -18,7 +18,6 @@ pub struct Lazy { // We never call `lock.init()`, so it is UB to attempt to acquire this mutex reentrantly! lock: Mutex, ptr: Cell<*mut Arc>, - init: fn() -> Arc, } #[inline] @@ -26,33 +25,32 @@ const fn done() -> *mut Arc { 1_usize as *mut _ } unsafe impl Sync for Lazy {} -impl Lazy { - /// Safety: `init` must not call `get` on the variable that is being - /// initialized. - pub const unsafe fn new(init: fn() -> Arc) -> Lazy { +impl Lazy { + pub const fn new() -> Lazy { Lazy { lock: Mutex::new(), ptr: Cell::new(ptr::null_mut()), - init, } } +} - pub fn get(&'static self) -> Option> { - 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 Lazy { + /// Safety: `init` must not call `get` on the variable that is being + /// initialized. + pub unsafe fn get(&'static self, init: fn() -> Arc) -> Option> { + 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 { + unsafe fn init(&'static self, init: fn() -> Arc) -> Arc { // 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 @@ impl Lazy { }); // 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()))); } diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index 1f256f518c7ce..a413432cdaabc 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -197,9 +197,11 @@ pub struct StdinLock<'a> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn stdin() -> Stdin { - static INSTANCE: Lazy>>> = unsafe { Lazy::new(stdin_init) }; + static INSTANCE: Lazy>>> = 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>>> { @@ -396,10 +398,11 @@ pub struct StdoutLock<'a> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn stdout() -> Stdout { - static INSTANCE: Lazy>>>> - = unsafe { Lazy::new(stdout_init) }; + static INSTANCE: Lazy>>>> = 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>>>> { @@ -533,10 +536,11 @@ pub struct StderrLock<'a> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn stderr() -> Stderr { - static INSTANCE: Lazy>>> = - unsafe { Lazy::new(stderr_init) }; + static INSTANCE: Lazy>>> = 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>>> { diff --git a/src/libsyntax/attr/builtin.rs b/src/libsyntax/attr/builtin.rs index ecd52a62eab26..3eecdf14a4e50 100644 --- a/src/libsyntax/attr/builtin.rs +++ b/src/libsyntax/attr/builtin.rs @@ -107,7 +107,11 @@ pub struct Stability { pub level: StabilityLevel, pub feature: Symbol, pub rustc_depr: Option, - pub rustc_const_unstable: Option, + /// `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, } /// 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 = None; let mut rustc_depr: Option = None; - let mut rustc_const_unstable: Option = None; + let mut rustc_const_unstable: Option = 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| { @@ -272,9 +272,7 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, 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 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, }, feature, rustc_depr: None, - rustc_const_unstable: None, + const_stability: None, }) } (None, _, _) => { @@ -379,7 +377,7 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, }, feature, rustc_depr: None, - rustc_const_unstable: None, + const_stability: None, }) } (None, _) => { @@ -412,9 +410,9 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, } // 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 \ diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs index cd9d76822106c..19bbbceff5fc0 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/libsyntax/attr/mod.rs @@ -15,7 +15,7 @@ mod builtin; 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::*; diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 080860f17f5dd..f226c9dd979d4 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -40,6 +40,16 @@ use symbol::{keywords, Symbol}; 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 @@ declare_features! ( // #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 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { 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 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { 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(..) => { diff --git a/src/test/mir-opt/lower_128bit_test.rs b/src/test/mir-opt/lower_128bit_test.rs index b4b54e13a698e..72c0e33cd9ecf 100644 --- a/src/test/mir-opt/lower_128bit_test.rs +++ b/src/test/mir-opt/lower_128bit_test.rs @@ -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 diff --git a/src/test/run-pass/invalid_const_promotion.rs b/src/test/run-pass/invalid_const_promotion.rs index 53cb4c4b009e5..a18d82fb7a4e7 100644 --- a/src/test/run-pass/invalid_const_promotion.rs +++ b/src/test/run-pass/invalid_const_promotion.rs @@ -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 @@ extern crate libc; 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() { diff --git a/src/test/ui/consts/const-size_of-cycle.stderr b/src/test/ui/consts/const-size_of-cycle.stderr index 16d87f7e31c9b..ab8b5792e681d 100644 --- a/src/test/ui/consts/const-size_of-cycle.stderr +++ b/src/test/ui/consts/const-size_of-cycle.stderr @@ -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::() } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | intrinsics::size_of::() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ = 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::() } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | intrinsics::size_of::() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ 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 index 0000000000000..b156e5a9731da --- /dev/null +++ b/src/test/ui/consts/min_const_fn/min_const_fn.nll.stderr @@ -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: 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: 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 Foo { + | ^ + +error: trait bounds other than `Sized` on const fn parameters are unstable + --> $DIR/min_const_fn.rs:126:6 + | +LL | impl Foo { + | ^ + +error: trait bounds other than `Sized` on const fn parameters are unstable + --> $DIR/min_const_fn.rs:131:6 + | +LL | impl Foo { + | ^ + +error: `impl Trait` in const fn is unstable + --> $DIR/min_const_fn.rs:137:1 + | +LL | const fn no_rpit2() -> AlanTuring { 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) {} + | ^^^^^^^^^^^^^^^^^^^^ + +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 index 0000000000000..b861e312d4245 --- /dev/null +++ b/src/test/ui/consts/min_const_fn/min_const_fn.rs @@ -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 or the MIT license +// , 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(x: T) -> T { x } +const fn foo7() { + ( + foo1(), + foo2(420), + foo3(69), + ).0 +} +const fn foo12(t: T) -> T { t } +const fn foo13(t: &T) -> &T { t } +const fn foo14<'a, T: 'a>(t: &'a T) -> &'a T { t } +const fn foo15(t: T) -> T where T: Sized { t } +const fn foo15_2(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: 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); +impl Foo { + 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 { + 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 Foo { + 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 Foo { + 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() -> *const T { 0 as *const T } +const unsafe fn foo6() -> *mut T { 0 as *mut T } + +// not ok +const fn foo11(t: T) -> T { t } +//~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable +const fn foo11_2(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 Foo { +//~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable + const fn foo(&self) {} +} + +impl Foo { +//~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable + const fn foo2(&self) {} +} + +impl Foo { +//~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable + const fn foo3(&self) {} +} + +struct AlanTuring(T); +const fn no_rpit2() -> AlanTuring { AlanTuring(0) } +//~^ ERROR `impl Trait` in const fn is unstable +const fn no_apit2(_x: AlanTuring) {} +//~^ 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 index 0000000000000..019948c31b15c --- /dev/null +++ b/src/test/ui/consts/min_const_fn/min_const_fn.stderr @@ -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: 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: 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 Foo { + | ^ + +error: trait bounds other than `Sized` on const fn parameters are unstable + --> $DIR/min_const_fn.rs:126:6 + | +LL | impl Foo { + | ^ + +error: trait bounds other than `Sized` on const fn parameters are unstable + --> $DIR/min_const_fn.rs:131:6 + | +LL | impl Foo { + | ^ + +error: `impl Trait` in const fn is unstable + --> $DIR/min_const_fn.rs:137:1 + | +LL | const fn no_rpit2() -> AlanTuring { 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) {} + | ^^^^^^^^^^^^^^^^^^^^ + +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 index 0000000000000..cfcc7990fb30d --- /dev/null +++ b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.nll.stderr @@ -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 index 0000000000000..38e2825643009 --- /dev/null +++ b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs @@ -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 or the MIT license +// , 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 index 0000000000000..3a1055f2ede15 --- /dev/null +++ b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr @@ -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 index 0000000000000..100d275f97e73 --- /dev/null +++ b/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.rs @@ -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 or the MIT license +// , 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 index 0000000000000..c10af3d2c8e71 --- /dev/null +++ b/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.stderr @@ -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 index 0000000000000..4ce62ecc48533 --- /dev/null +++ b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs @@ -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 or the MIT license +// , 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 index 0000000000000..8e47090890db3 --- /dev/null +++ b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr @@ -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 index 0000000000000..e7caa4c6cb426 --- /dev/null +++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.rs @@ -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 or the MIT license +// , 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() -> *const T { 0 as *const T } +const unsafe fn foo6() -> *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::() } //~ ERROR unsafe operations are not allowed in const fn +} +const fn foo10() -> *const Vec> { + unsafe { foo6::>>() } //~ 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 index 0000000000000..17cba8569c148 --- /dev/null +++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr @@ -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::() } //~ 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::>>() } //~ 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`. diff --git a/src/test/ui/error-codes/E0308.stderr b/src/test/ui/error-codes/E0308.stderr index 490a8e0ff0f1d..438dd50f2bfa8 100644 --- a/src/test/ui/error-codes/E0308.stderr +++ b/src/test/ui/error-codes/E0308.stderr @@ -4,8 +4,8 @@ error[E0308]: intrinsic has wrong type LL | fn size_of(); //~ 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 diff --git a/src/test/ui/feature-gates/feature-gate-const_fn.rs b/src/test/ui/feature-gates/feature-gate-const_fn.rs index 1d1dedddaaa3e..f774658975b79 100644 --- a/src/test/ui/feature-gates/feature-gate-const_fn.rs +++ b/src/test/ui/feature-gates/feature-gate-const_fn.rs @@ -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 @@ trait Foo { } 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(); diff --git a/src/test/ui/feature-gates/feature-gate-const_fn.stderr b/src/test/ui/feature-gates/feature-gate-const_fn.stderr index d7c00a3e0cb40..26c0c7877b4ec 100644 --- a/src/test/ui/feature-gates/feature-gate-const_fn.stderr +++ b/src/test/ui/feature-gates/feature-gate-const_fn.stderr @@ -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 index 0000000000000..e052ba9c8b43a --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-min_const_fn.rs @@ -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 or the MIT license +// , 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 index 0000000000000..aa7750362b2fd --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-min_const_fn.stderr @@ -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`. From 7b3d930ca6f8269d07bce30ace4a9be2f316a63a Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 29 Aug 2018 13:00:14 +0200 Subject: [PATCH 2/6] Libstd only has `min_const_fn` const fns --- src/libstd/lib.rs | 3 +- .../min_const_fn/min_const_fn_libstd.rs | 38 +++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/consts/min_const_fn/min_const_fn_libstd.rs diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 310475d31fded..e7195b3e21ee3 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -250,7 +250,8 @@ #![feature(cfg_target_vendor)] #![feature(char_error_internals)] #![feature(compiler_builtins_lib)] -#![feature(const_fn)] +#![cfg_attr(stage0, feature(const_fn))] +#![cfg_attr(not(stage0), feature(min_const_fn))] #![feature(const_int_ops)] #![feature(const_ip)] #![feature(core_intrinsics)] diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_libstd.rs b/src/test/ui/consts/min_const_fn/min_const_fn_libstd.rs new file mode 100644 index 0000000000000..fcc9545d97f15 --- /dev/null +++ b/src/test/ui/consts/min_const_fn/min_const_fn_libstd.rs @@ -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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(integer_atomics, min_const_fn)] + +// compile-pass + +use std::cell::UnsafeCell; +use std::sync::atomic::AtomicU32; +pub struct Condvar { + condvar: UnsafeCell, +} + +unsafe impl Send for Condvar {} +unsafe impl Sync for Condvar {} + +#[repr(C)] +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +struct NoWait(u32); + +const CONDVAR_HAS_NO_WAITERS: NoWait = NoWait(42); + +impl Condvar { + pub const fn new() -> Condvar { + Condvar { + condvar: UnsafeCell::new(AtomicU32::new(CONDVAR_HAS_NO_WAITERS.0)), + } + } +} + +fn main() {} From d125e904b5e298f710c7a5a1aaa3ebd953d2ced3 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 29 Aug 2018 13:20:43 +0200 Subject: [PATCH 3/6] Restrict most uses of `const_fn` to `min_const_fn` --- src/liballoc/lib.rs | 3 ++- src/liballoc/tests/lib.rs | 3 ++- src/librustc/lib.rs | 3 ++- src/librustc_mir/lib.rs | 1 - src/librustc_target/lib.rs | 3 ++- .../codegen-units/item-collection/unreferenced-const-fn.rs | 2 +- src/test/codegen/link-dead-code.rs | 2 +- src/test/compile-fail/issue-43733-2.rs | 2 +- src/test/mir-opt/lower_128bit_debug_test.rs | 2 +- src/test/mir-opt/lower_128bit_test.rs | 2 +- src/test/run-fail/issue-29798.rs | 2 +- src/test/run-pass/auxiliary/const_fn_lib.rs | 2 +- src/test/run-pass/auxiliary/issue-36954.rs | 2 +- src/test/run-pass/const-fn-const-eval.rs | 2 +- src/test/run-pass/const-fn-method.rs | 2 +- src/test/run-pass/const-fn-nested.rs | 2 +- src/test/run-pass/const-meth-pattern.rs | 2 +- src/test/run-pass/const-pattern-variant.rs | 2 +- src/test/run-pass/const-size_of-align_of.rs | 2 +- src/test/run-pass/const-unsafe-fn.rs | 2 +- src/test/run-pass/consts-in-patterns.rs | 2 +- src/test/run-pass/ctfe/ice-48279.rs | 2 +- src/test/run-pass/ctfe/match-const-fn-structs.rs | 2 +- src/test/run-pass/ctfe/return-in-const-fn.rs | 2 +- src/test/run-pass/issue-28822.rs | 2 +- src/test/run-pass/issue-29927.rs | 2 +- src/test/run-pass/issue-33537.rs | 2 +- src/test/run-pass/issue-37991.rs | 2 +- src/test/run-pass/issue29927-1.rs | 2 +- src/test/rustdoc/auxiliary/issue-27362.rs | 2 +- src/test/rustdoc/const-fn.rs | 2 +- src/test/rustdoc/const.rs | 2 +- src/test/ui/borrowck/move-in-static-initializer-issue-38520.rs | 2 +- src/test/ui/consts/auxiliary/const_fn_lib.rs | 2 +- src/test/ui/consts/const-eval/issue-43197.rs | 2 +- src/test/ui/consts/const-eval/issue-47971.rs | 2 +- src/test/ui/consts/const-pattern-not-const-evaluable.rs | 2 +- src/test/ui/consts/const-size_of-cycle.rs | 2 -- src/test/ui/infinite/infinite-recursion-const-fn.rs | 2 +- src/test/ui/issues/issue-44415.rs | 2 +- src/test/ui/unsafe/unsafe-const-fn.rs | 2 +- 41 files changed, 43 insertions(+), 42 deletions(-) diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 676c977514f32..452d2b1472ff4 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -88,7 +88,8 @@ #![feature(box_syntax)] #![feature(cfg_target_has_atomic)] #![feature(coerce_unsized)] -#![feature(const_fn)] +#![cfg_attr(stage0, feature(const_fn))] +#![cfg_attr(not(stage0), feature(min_const_fn))] #![feature(core_intrinsics)] #![feature(custom_attribute)] #![feature(dropck_eyepatch)] diff --git a/src/liballoc/tests/lib.rs b/src/liballoc/tests/lib.rs index 3a84f9e7e47ba..710c659ac5396 100644 --- a/src/liballoc/tests/lib.rs +++ b/src/liballoc/tests/lib.rs @@ -11,7 +11,8 @@ #![feature(allocator_api)] #![feature(alloc_system)] #![feature(box_syntax)] -#![feature(const_fn)] +#![cfg_attr(stage0, feature(const_fn))] +#![cfg_attr(not(stage0), feature(min_const_fn))] #![feature(drain_filter)] #![feature(exact_size_is_empty)] #![feature(pattern)] diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index d014f319564fe..d79281666d639 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -42,7 +42,8 @@ #![feature(box_patterns)] #![feature(box_syntax)] -#![feature(const_fn)] +#![cfg_attr(stage0, feature(const_fn))] +#![cfg_attr(not(stage0), feature(min_const_fn))] #![feature(core_intrinsics)] #![feature(drain_filter)] #![cfg_attr(windows, feature(libc))] diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index f91ff3642cd10..6f087221b8024 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -23,7 +23,6 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(box_patterns)] #![feature(box_syntax)] #![feature(crate_visibility_modifier)] -#![feature(const_fn)] #![feature(core_intrinsics)] #![feature(decl_macro)] #![cfg_attr(stage0, feature(macro_vis_matcher))] diff --git a/src/librustc_target/lib.rs b/src/librustc_target/lib.rs index 1e70a806cce89..e4d958e3b6f35 100644 --- a/src/librustc_target/lib.rs +++ b/src/librustc_target/lib.rs @@ -22,7 +22,8 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(box_syntax)] -#![feature(const_fn)] +#![cfg_attr(stage0, feature(const_fn))] +#![cfg_attr(not(stage0), feature(min_const_fn))] #![cfg_attr(not(stage0), feature(nll))] #![cfg_attr(not(stage0), feature(infer_outlives_requirements))] #![feature(slice_patterns)] diff --git a/src/test/codegen-units/item-collection/unreferenced-const-fn.rs b/src/test/codegen-units/item-collection/unreferenced-const-fn.rs index c2ff846721c5f..1462417643600 100644 --- a/src/test/codegen-units/item-collection/unreferenced-const-fn.rs +++ b/src/test/codegen-units/item-collection/unreferenced-const-fn.rs @@ -13,7 +13,7 @@ // NB: We do not expect *any* monomorphization to be generated here. -#![feature(const_fn)] +#![feature(min_const_fn)] #![deny(dead_code)] #![crate_type = "rlib"] diff --git a/src/test/codegen/link-dead-code.rs b/src/test/codegen/link-dead-code.rs index 9cabcd9157a6a..3ea20aa921e1b 100644 --- a/src/test/codegen/link-dead-code.rs +++ b/src/test/codegen/link-dead-code.rs @@ -10,7 +10,7 @@ // compile-flags:-Clink-dead-code -#![feature(const_fn)] +#![feature(min_const_fn)] #![crate_type = "rlib"] // This test makes sure that, when -Clink-dead-code is specified, we generate diff --git a/src/test/compile-fail/issue-43733-2.rs b/src/test/compile-fail/issue-43733-2.rs index a5ba9ef9bd35d..fea81f0cc8fa4 100644 --- a/src/test/compile-fail/issue-43733-2.rs +++ b/src/test/compile-fail/issue-43733-2.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(const_fn)] +#![feature(min_const_fn)] #![feature(cfg_target_thread_local, thread_local_internals)] // On platforms *without* `#[thread_local]`, use diff --git a/src/test/mir-opt/lower_128bit_debug_test.rs b/src/test/mir-opt/lower_128bit_debug_test.rs index 646c4312fc21f..1bf740fdec619 100644 --- a/src/test/mir-opt/lower_128bit_debug_test.rs +++ b/src/test/mir-opt/lower_128bit_debug_test.rs @@ -15,7 +15,7 @@ // compile-flags: -Z lower_128bit_ops=yes -C debug_assertions=yes -#![feature(const_fn)] +#![feature(min_const_fn)] static TEST_SIGNED: i128 = const_signed(-222); static TEST_UNSIGNED: u128 = const_unsigned(200); diff --git a/src/test/mir-opt/lower_128bit_test.rs b/src/test/mir-opt/lower_128bit_test.rs index 72c0e33cd9ecf..235df8a6785d4 100644 --- a/src/test/mir-opt/lower_128bit_test.rs +++ b/src/test/mir-opt/lower_128bit_test.rs @@ -12,7 +12,7 @@ // compile-flags: -Z lower_128bit_ops=yes -C debug_assertions=no -O -#![feature(const_fn)] +#![feature(min_const_fn)] static TEST_SIGNED: i128 = const_signed(-222); static TEST_UNSIGNED: u128 = const_unsigned(200); diff --git a/src/test/run-fail/issue-29798.rs b/src/test/run-fail/issue-29798.rs index a77175975f941..30efe3b9ab2c4 100644 --- a/src/test/run-fail/issue-29798.rs +++ b/src/test/run-fail/issue-29798.rs @@ -10,7 +10,7 @@ // error-pattern:index out of bounds: the len is 5 but the index is 5 -#![feature(const_fn)] +#![feature(min_const_fn)] const fn test(x: usize) -> i32 { [42;5][x] } diff --git a/src/test/run-pass/auxiliary/const_fn_lib.rs b/src/test/run-pass/auxiliary/const_fn_lib.rs index be06e8dd5700b..6985a6527c874 100644 --- a/src/test/run-pass/auxiliary/const_fn_lib.rs +++ b/src/test/run-pass/auxiliary/const_fn_lib.rs @@ -11,6 +11,6 @@ // Crate that exports a const fn. Used for testing cross-crate. #![crate_type="rlib"] -#![feature(const_fn)] +#![feature(min_const_fn)] pub const fn foo() -> usize { 22 } diff --git a/src/test/run-pass/auxiliary/issue-36954.rs b/src/test/run-pass/auxiliary/issue-36954.rs index 832ee1d7c1b45..5351a40916b7d 100644 --- a/src/test/run-pass/auxiliary/issue-36954.rs +++ b/src/test/run-pass/auxiliary/issue-36954.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(const_fn)] +#![feature(min_const_fn)] #![crate_type = "lib"] const fn foo(i: i32) -> i32 { diff --git a/src/test/run-pass/const-fn-const-eval.rs b/src/test/run-pass/const-fn-const-eval.rs index 77c70fe7f6354..3fe27ca200cb0 100644 --- a/src/test/run-pass/const-fn-const-eval.rs +++ b/src/test/run-pass/const-fn-const-eval.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(const_fn)] +#![feature(min_const_fn)] const fn add(x: usize, y: usize) -> usize { x + y diff --git a/src/test/run-pass/const-fn-method.rs b/src/test/run-pass/const-fn-method.rs index 7d8d941439cf8..bed78f1e8978f 100644 --- a/src/test/run-pass/const-fn-method.rs +++ b/src/test/run-pass/const-fn-method.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(const_fn)] +#![feature(min_const_fn)] struct Foo { value: u32 } diff --git a/src/test/run-pass/const-fn-nested.rs b/src/test/run-pass/const-fn-nested.rs index 86f5dedc4d1b1..d5959a89e51a5 100644 --- a/src/test/run-pass/const-fn-nested.rs +++ b/src/test/run-pass/const-fn-nested.rs @@ -10,7 +10,7 @@ // Test a call whose argument is the result of another call. -#![feature(const_fn)] +#![feature(min_const_fn)] const fn sub(x: u32, y: u32) -> u32 { x - y diff --git a/src/test/run-pass/const-meth-pattern.rs b/src/test/run-pass/const-meth-pattern.rs index 3b27987f190cd..836716051d213 100644 --- a/src/test/run-pass/const-meth-pattern.rs +++ b/src/test/run-pass/const-meth-pattern.rs @@ -7,7 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(const_fn)] +#![feature(min_const_fn)] struct A; diff --git a/src/test/run-pass/const-pattern-variant.rs b/src/test/run-pass/const-pattern-variant.rs index 104ab6e19db67..689ae19e7d4f4 100644 --- a/src/test/run-pass/const-pattern-variant.rs +++ b/src/test/run-pass/const-pattern-variant.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(const_fn)] +#![feature(min_const_fn)] #[derive(PartialEq, Eq)] enum Cake { diff --git a/src/test/run-pass/const-size_of-align_of.rs b/src/test/run-pass/const-size_of-align_of.rs index 06fbe9bf4f639..245dd673b512c 100644 --- a/src/test/run-pass/const-size_of-align_of.rs +++ b/src/test/run-pass/const-size_of-align_of.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(const_fn)] +#![feature(min_const_fn)] use std::mem; diff --git a/src/test/run-pass/const-unsafe-fn.rs b/src/test/run-pass/const-unsafe-fn.rs index 2511cfd042206..b267245b78969 100644 --- a/src/test/run-pass/const-unsafe-fn.rs +++ b/src/test/run-pass/const-unsafe-fn.rs @@ -10,7 +10,7 @@ // A quick test of 'unsafe const fn' functionality -#![feature(const_fn)] +#![feature(min_const_fn)] const unsafe fn dummy(v: u32) -> u32 { !v diff --git a/src/test/run-pass/consts-in-patterns.rs b/src/test/run-pass/consts-in-patterns.rs index eec4c940585c0..574fb29e82c7d 100644 --- a/src/test/run-pass/consts-in-patterns.rs +++ b/src/test/run-pass/consts-in-patterns.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(const_fn)] +#![feature(min_const_fn)] const FOO: isize = 10; const BAR: isize = 3; diff --git a/src/test/run-pass/ctfe/ice-48279.rs b/src/test/run-pass/ctfe/ice-48279.rs index c435e5fdaab4a..f59a6810e3a78 100644 --- a/src/test/run-pass/ctfe/ice-48279.rs +++ b/src/test/run-pass/ctfe/ice-48279.rs @@ -10,7 +10,7 @@ // https://github.com/rust-lang/rust/issues/48279 -#![feature(const_fn)] +#![feature(min_const_fn)] #[derive(PartialEq, Eq)] pub struct NonZeroU32 { diff --git a/src/test/run-pass/ctfe/match-const-fn-structs.rs b/src/test/run-pass/ctfe/match-const-fn-structs.rs index 0bb253d1a6455..352958f4c6a45 100644 --- a/src/test/run-pass/ctfe/match-const-fn-structs.rs +++ b/src/test/run-pass/ctfe/match-const-fn-structs.rs @@ -10,7 +10,7 @@ // https://github.com/rust-lang/rust/issues/46114 -#![feature(const_fn)] +#![feature(min_const_fn)] #[derive(Eq, PartialEq)] struct A { value: u32 } diff --git a/src/test/run-pass/ctfe/return-in-const-fn.rs b/src/test/run-pass/ctfe/return-in-const-fn.rs index d57d3bcb49aa8..87fdac4bfb4fe 100644 --- a/src/test/run-pass/ctfe/return-in-const-fn.rs +++ b/src/test/run-pass/ctfe/return-in-const-fn.rs @@ -10,7 +10,7 @@ // https://github.com/rust-lang/rust/issues/43754 -#![feature(const_fn)] +#![feature(min_const_fn)] const fn foo(x: usize) -> usize { return x; } diff --git a/src/test/run-pass/issue-28822.rs b/src/test/run-pass/issue-28822.rs index 5a010f2be7a34..10482139a978c 100644 --- a/src/test/run-pass/issue-28822.rs +++ b/src/test/run-pass/issue-28822.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(const_fn)] +#![feature(min_const_fn)] fn main() {} diff --git a/src/test/run-pass/issue-29927.rs b/src/test/run-pass/issue-29927.rs index 6d9adbcd57980..3079d9de3c238 100644 --- a/src/test/run-pass/issue-29927.rs +++ b/src/test/run-pass/issue-29927.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(const_fn)] +#![feature(min_const_fn)] struct A { field: usize, } diff --git a/src/test/run-pass/issue-33537.rs b/src/test/run-pass/issue-33537.rs index 24f4c9f590b11..7be79f3a45097 100644 --- a/src/test/run-pass/issue-33537.rs +++ b/src/test/run-pass/issue-33537.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(const_fn)] +#![feature(min_const_fn)] const fn foo() -> *const i8 { b"foo" as *const _ as *const i8 diff --git a/src/test/run-pass/issue-37991.rs b/src/test/run-pass/issue-37991.rs index 9bdde02d0061c..9b3289e67859a 100644 --- a/src/test/run-pass/issue-37991.rs +++ b/src/test/run-pass/issue-37991.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(const_fn)] +#![feature(min_const_fn)] const fn foo() -> i64 { 3 diff --git a/src/test/run-pass/issue29927-1.rs b/src/test/run-pass/issue29927-1.rs index 68271accb61a2..488bc6e6927a0 100644 --- a/src/test/run-pass/issue29927-1.rs +++ b/src/test/run-pass/issue29927-1.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(const_fn)] +#![feature(min_const_fn)] const fn f() -> usize { 5 } diff --git a/src/test/rustdoc/auxiliary/issue-27362.rs b/src/test/rustdoc/auxiliary/issue-27362.rs index 25de698cad10e..0c1eedc86ccfd 100644 --- a/src/test/rustdoc/auxiliary/issue-27362.rs +++ b/src/test/rustdoc/auxiliary/issue-27362.rs @@ -10,7 +10,7 @@ // compile-flags: -Cmetadata=aux -#![feature(const_fn)] +#![feature(min_const_fn)] pub const fn foo() {} pub const unsafe fn bar() {} diff --git a/src/test/rustdoc/const-fn.rs b/src/test/rustdoc/const-fn.rs index c323681f60b0a..dc7a2799b46a9 100644 --- a/src/test/rustdoc/const-fn.rs +++ b/src/test/rustdoc/const-fn.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(const_fn)] +#![feature(min_const_fn)] #![crate_name = "foo"] // @has foo/fn.bar.html diff --git a/src/test/rustdoc/const.rs b/src/test/rustdoc/const.rs index 380feb941d6fe..49694e3ae08d1 100644 --- a/src/test/rustdoc/const.rs +++ b/src/test/rustdoc/const.rs @@ -10,7 +10,7 @@ #![crate_type="lib"] -#![feature(const_fn)] +#![feature(min_const_fn)] pub struct Foo; diff --git a/src/test/ui/borrowck/move-in-static-initializer-issue-38520.rs b/src/test/ui/borrowck/move-in-static-initializer-issue-38520.rs index 508e09318ae11..d71c8462587d0 100644 --- a/src/test/ui/borrowck/move-in-static-initializer-issue-38520.rs +++ b/src/test/ui/borrowck/move-in-static-initializer-issue-38520.rs @@ -15,7 +15,7 @@ // permitted as `Foo` is not copy (even in a static/const // initializer). -#![feature(const_fn)] +#![feature(min_const_fn)] struct Foo(usize); diff --git a/src/test/ui/consts/auxiliary/const_fn_lib.rs b/src/test/ui/consts/auxiliary/const_fn_lib.rs index b0d5a6b12727b..499227e71a74c 100644 --- a/src/test/ui/consts/auxiliary/const_fn_lib.rs +++ b/src/test/ui/consts/auxiliary/const_fn_lib.rs @@ -11,6 +11,6 @@ // Crate that exports a const fn. Used for testing cross-crate. #![crate_type="rlib"] -#![feature(const_fn)] +#![feature(min_const_fn)] pub const fn foo() -> usize { 22 } //~ ERROR const fn is unstable diff --git a/src/test/ui/consts/const-eval/issue-43197.rs b/src/test/ui/consts/const-eval/issue-43197.rs index c0b45f0ba3041..200f423f6e39b 100644 --- a/src/test/ui/consts/const-eval/issue-43197.rs +++ b/src/test/ui/consts/const-eval/issue-43197.rs @@ -10,7 +10,7 @@ #![warn(const_err)] -#![feature(const_fn)] +#![feature(min_const_fn)] const fn foo(x: u32) -> u32 { x diff --git a/src/test/ui/consts/const-eval/issue-47971.rs b/src/test/ui/consts/const-eval/issue-47971.rs index f6a2db31d371a..2bc860e3ef94f 100644 --- a/src/test/ui/consts/const-eval/issue-47971.rs +++ b/src/test/ui/consts/const-eval/issue-47971.rs @@ -10,7 +10,7 @@ // compile-pass -#![feature(const_fn)] +#![feature(min_const_fn)] struct S(pub &'static u32, pub u32); diff --git a/src/test/ui/consts/const-pattern-not-const-evaluable.rs b/src/test/ui/consts/const-pattern-not-const-evaluable.rs index 87d5e13df6eb3..4f02b1eef3a0f 100644 --- a/src/test/ui/consts/const-pattern-not-const-evaluable.rs +++ b/src/test/ui/consts/const-pattern-not-const-evaluable.rs @@ -10,7 +10,7 @@ // compile-pass -#![feature(const_fn)] +#![feature(min_const_fn)] #[derive(PartialEq, Eq)] enum Cake { diff --git a/src/test/ui/consts/const-size_of-cycle.rs b/src/test/ui/consts/const-size_of-cycle.rs index fed8e1885de8a..04c054f8b6db2 100644 --- a/src/test/ui/consts/const-size_of-cycle.rs +++ b/src/test/ui/consts/const-size_of-cycle.rs @@ -10,8 +10,6 @@ // error-pattern: cycle detected -#![feature(const_fn)] - struct Foo { bytes: [u8; std::mem::size_of::()] } diff --git a/src/test/ui/infinite/infinite-recursion-const-fn.rs b/src/test/ui/infinite/infinite-recursion-const-fn.rs index 4f1f67214509e..63ae18cf9c2fa 100644 --- a/src/test/ui/infinite/infinite-recursion-const-fn.rs +++ b/src/test/ui/infinite/infinite-recursion-const-fn.rs @@ -10,7 +10,7 @@ //https://github.com/rust-lang/rust/issues/31364 -#![feature(const_fn)] +#![feature(min_const_fn)] const fn a() -> usize { b() } const fn b() -> usize { a() } const ARR: [i32; a()] = [5; 6]; //~ ERROR could not evaluate constant expression diff --git a/src/test/ui/issues/issue-44415.rs b/src/test/ui/issues/issue-44415.rs index 5d295510844ab..bd50f93945c51 100644 --- a/src/test/ui/issues/issue-44415.rs +++ b/src/test/ui/issues/issue-44415.rs @@ -10,7 +10,7 @@ //~^^^^^^^^^^ ERROR cycle detected when computing layout of -#![feature(const_fn)] + #![feature(core_intrinsics)] use std::intrinsics; diff --git a/src/test/ui/unsafe/unsafe-const-fn.rs b/src/test/ui/unsafe/unsafe-const-fn.rs index 765e2059a4b5e..fe0bb7533a86f 100644 --- a/src/test/ui/unsafe/unsafe-const-fn.rs +++ b/src/test/ui/unsafe/unsafe-const-fn.rs @@ -10,7 +10,7 @@ // A quick test of 'unsafe const fn' functionality -#![feature(const_fn)] +#![feature(min_const_fn)] const unsafe fn dummy(v: u32) -> u32 { !v From f3e1b968e3ac62cec168085ba0f9967fac9c4937 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 30 Aug 2018 10:39:41 +0200 Subject: [PATCH 4/6] Add test that min const fns can't call unstable min const fns even with the feature gate active --- .../min_const_fn/min_const_fn_libstd_stability.rs | 10 +++++++++- .../min_const_fn/min_const_fn_libstd_stability.stderr | 8 +++++++- 2 files changed, 16 insertions(+), 2 deletions(-) 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 index 4ce62ecc48533..9f5d0ad5df3e1 100644 --- 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 @@ -13,7 +13,7 @@ we're apparently really bad at it", issue = "0")] -#![feature(rustc_const_unstable, const_fn, foo)] +#![feature(rustc_const_unstable, const_fn, foo, foo2)] #![feature(staged_api)] #[stable(feature = "rust1", since = "1.0.0")] @@ -35,4 +35,12 @@ const fn bar2() -> u32 { foo2() } //~ ERROR can only call other `min_const_fn` // conformity is required, even with `const_fn` feature gate const fn bar3() -> u32 { (5f32 + 6f32) as u32 } //~ ERROR only int, `bool` and `char` operations +// check whether this function cannot be called even with the feature gate active +#[unstable(feature = "foo2", issue="0")] +const fn foo2_gated() -> u32 { 42 } + +#[stable(feature = "rust1", since = "1.0.0")] +// can't call non-min_const_fn +const fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR can only call other `min_const_fn` + 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 index 8e47090890db3..1ef7ffd3a916e 100644 --- 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 @@ -16,5 +16,11 @@ error: only int, `bool` and `char` operations are stable in const fn LL | const fn bar3() -> u32 { (5f32 + 6f32) as u32 } //~ ERROR only int, `bool` and `char` operations | ^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error: can only call other `min_const_fn` within a `min_const_fn` + --> $DIR/min_const_fn_libstd_stability.rs:44:32 + | +LL | const fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR can only call other `min_const_fn` + | ^^^^^^^^^^^^ + +error: aborting due to 4 previous errors From b68bb636c7f238dbf94f1cbf301eafac0d308393 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 30 Aug 2018 10:45:05 +0200 Subject: [PATCH 5/6] Make `Condvar::new` and `RWLock::new` min const fn for cloudabi --- src/libstd/sys/cloudabi/condvar.rs | 8 +++++--- src/libstd/sys/cloudabi/rwlock.rs | 8 +++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/libstd/sys/cloudabi/condvar.rs b/src/libstd/sys/cloudabi/condvar.rs index c05c837ade274..ccf848a9be420 100644 --- a/src/libstd/sys/cloudabi/condvar.rs +++ b/src/libstd/sys/cloudabi/condvar.rs @@ -28,11 +28,13 @@ pub struct Condvar { unsafe impl Send for Condvar {} unsafe impl Sync for Condvar {} +const NEW: Condvar = Condvar { + condvar: UnsafeCell::new(AtomicU32::new(abi::CONDVAR_HAS_NO_WAITERS.0)), +}; + impl Condvar { pub const fn new() -> Condvar { - Condvar { - condvar: UnsafeCell::new(AtomicU32::new(abi::CONDVAR_HAS_NO_WAITERS.0)), - } + NEW } pub unsafe fn init(&mut self) {} diff --git a/src/libstd/sys/cloudabi/rwlock.rs b/src/libstd/sys/cloudabi/rwlock.rs index 8539aec5e2c07..dc8624ec8a1b8 100644 --- a/src/libstd/sys/cloudabi/rwlock.rs +++ b/src/libstd/sys/cloudabi/rwlock.rs @@ -32,11 +32,13 @@ pub unsafe fn raw(r: &RWLock) -> *mut AtomicU32 { unsafe impl Send for RWLock {} unsafe impl Sync for RWLock {} +const NEW: RWLock = RWLock { + lock: UnsafeCell::new(AtomicU32::new(abi::LOCK_UNLOCKED.0)), +}; + impl RWLock { pub const fn new() -> RWLock { - RWLock { - lock: UnsafeCell::new(AtomicU32::new(abi::LOCK_UNLOCKED.0)), - } + NEW } pub unsafe fn try_read(&self) -> bool { From 2839f4f0e8d58c295e146999961b78e2cc47354f Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 31 Aug 2018 11:47:45 +0200 Subject: [PATCH 6/6] Get rid of token passing --- .../transform/qualify_min_const_fn.rs | 90 ++++++++----------- 1 file changed, 35 insertions(+), 55 deletions(-) diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index 53ba4b03cb734..56e32ea5d1a23 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -5,17 +5,7 @@ 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)>; +type McfResult = Result<(), (Span, Cow<'static, str>)>; pub fn is_min_const_fn( tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -74,8 +64,6 @@ pub fn is_min_const_fn( } } - 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, @@ -83,30 +71,28 @@ pub fn is_min_const_fn( )); } for local in &mir.local_decls { - token = check_ty(tcx, local.ty, local.source_info.span, token)?; + check_ty(tcx, local.ty, local.source_info.span)?; } // impl trait is gone in MIR, so check the return type manually - token = check_ty( + 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)?; + check_terminator(tcx, mir, bb.terminator())?; for stmt in &bb.statements { - token = check_statement(tcx, mir, stmt, token)?; + check_statement(tcx, mir, stmt)?; } } - Ok(token) + Ok(()) } 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 { @@ -146,7 +132,7 @@ fn check_ty( _ => {} } } - Ok(token) + Ok(()) } fn check_rvalue( @@ -154,14 +140,13 @@ fn check_rvalue( 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) + check_operand(tcx, mir, operand, span) } Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) => { - check_place(tcx, mir, place, span, token, PlaceMode::Read) + check_place(tcx, mir, place, span, PlaceMode::Read) } Rvalue::Cast(_, operand, cast_ty) => { use rustc::ty::cast::CastTy; @@ -175,16 +160,16 @@ fn check_rvalue( (CastTy::RPtr(_), CastTy::Float) => bug!(), (CastTy::RPtr(_), CastTy::Int(_)) => bug!(), (CastTy::Ptr(_), CastTy::RPtr(_)) => bug!(), - _ => check_operand(tcx, mir, operand, span, token), + _ => check_operand(tcx, mir, operand, span), } } // 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)?; + check_operand(tcx, mir, lhs, span)?; + check_operand(tcx, mir, rhs, span)?; let ty = lhs.ty(mir, tcx); if ty.is_integral() || ty.is_bool() || ty.is_char() { - Ok(token) + Ok(()) } else { Err(( span, @@ -193,11 +178,11 @@ fn check_rvalue( } } // checked by regular const fn checks - Rvalue::NullaryOp(..) => Ok(token), + Rvalue::NullaryOp(..) => Ok(()), Rvalue::UnaryOp(_, operand) => { let ty = operand.ty(mir, tcx); if ty.is_integral() || ty.is_bool() { - check_operand(tcx, mir, operand, span, token) + check_operand(tcx, mir, operand, span) } else { Err(( span, @@ -206,11 +191,10 @@ fn check_rvalue( } } Rvalue::Aggregate(_, operands) => { - let mut token = token; for operand in operands { - token = check_operand(tcx, mir, operand, span, token)?; + check_operand(tcx, mir, operand, span)?; } - Ok(token) + Ok(()) } } } @@ -224,19 +208,18 @@ 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) + check_place(tcx, mir, place, span, PlaceMode::Assign)?; + check_rvalue(tcx, mir, rval, span) } StatementKind::ReadForMatch(_) => Err((span, "match in const fn is unstable".into())), // just an assignment - StatementKind::SetDiscriminant { .. } => Ok(token), + StatementKind::SetDiscriminant { .. } => Ok(()), | StatementKind::InlineAsm { .. } => { Err((span, "cannot use inline assembly in const fn".into())) @@ -248,7 +231,7 @@ fn check_statement( | StatementKind::Validate(..) | StatementKind::EndRegion(_) | StatementKind::UserAssertTy(..) - | StatementKind::Nop => Ok(token), + | StatementKind::Nop => Ok(()), } } @@ -257,13 +240,12 @@ fn check_operand( 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) + check_place(tcx, mir, place, span, PlaceMode::Read) } - Operand::Constant(_) => Ok(token), + Operand::Constant(_) => Ok(()), } } @@ -272,26 +254,25 @@ fn check_place( 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::Temp | LocalKind::ReturnPointer => Ok(()), LocalKind::Arg | LocalKind::Var => { Err((span, "assignments in const fn are unstable".into())) } }, - PlaceMode::Read => Ok(token), + PlaceMode::Read => Ok(()), }, // promoteds are always fine, they are essentially constants - Place::Promoted(_) => Ok(token), + Place::Promoted(_) => Ok(()), 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) + check_place(tcx, mir, &proj.base, span, mode) } // slice patterns are unstable | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => { @@ -309,20 +290,19 @@ 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::Resume => Ok(()), TerminatorKind::Drop { location, .. } => { - check_place(tcx, mir, location, span, token, PlaceMode::Read) + check_place(tcx, mir, location, span, PlaceMode::Read) } TerminatorKind::DropAndReplace { location, value, .. } => { - let token = check_place(tcx, mir, location, span, token, PlaceMode::Read)?; - check_operand(tcx, mir, value, span, token) + check_place(tcx, mir, location, span, PlaceMode::Read)?; + check_operand(tcx, mir, value, span) }, TerminatorKind::SwitchInt { .. } => Err(( span, @@ -344,12 +324,12 @@ fn check_terminator( 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)?; + check_operand(tcx, mir, func, span)?; for arg in args { - token = check_operand(tcx, mir, arg, span, token)?; + check_operand(tcx, mir, arg, span)?; } - Ok(token) + Ok(()) } else { Err(( span, @@ -367,7 +347,7 @@ fn check_terminator( msg: _, target: _, cleanup: _, - } => check_operand(tcx, mir, cond, span, token), + } => check_operand(tcx, mir, cond, span), | TerminatorKind::FalseEdges { .. } | TerminatorKind::FalseUnwind { .. } => span_bug!( terminator.source_info.span,