Implement the min_const_fn feature gate

This commit is contained in:
Oliver Schneider 2018-08-22 15:56:37 +02:00 committed by Oliver Schneider
parent 1114ab684f
commit 472ca71598
39 changed files with 1626 additions and 230 deletions

View File

@ -285,6 +285,15 @@ pub fn forget<T>(t: T) {
/// [alignment]: ./fn.align_of.html
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg(not(stage0))]
pub const fn size_of<T>() -> usize {
intrinsics::size_of::<T>()
}
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg(stage0)]
/// Ceci n'est pas la documentation
pub const fn size_of<T>() -> usize {
unsafe { intrinsics::size_of::<T>() }
}
@ -334,6 +343,16 @@ pub fn size_of_val<T: ?Sized>(val: &T) -> usize {
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_deprecated(reason = "use `align_of` instead", since = "1.2.0")]
#[cfg(not(stage0))]
pub fn min_align_of<T>() -> usize {
intrinsics::min_align_of::<T>()
}
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_deprecated(reason = "use `align_of` instead", since = "1.2.0")]
#[cfg(stage0)]
/// Ceci n'est pas la documentation
pub fn min_align_of<T>() -> usize {
unsafe { intrinsics::min_align_of::<T>() }
}
@ -376,6 +395,15 @@ pub fn min_align_of_val<T: ?Sized>(val: &T) -> usize {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg(not(stage0))]
pub const fn align_of<T>() -> usize {
intrinsics::min_align_of::<T>()
}
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg(stage0)]
/// Ceci n'est pas la documentation
pub const fn align_of<T>() -> usize {
unsafe { intrinsics::min_align_of::<T>() }
}

View File

@ -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);

View File

@ -130,7 +130,7 @@ impl_stable_hash_for!(struct ::syntax::attr::Stability {
level,
feature,
rustc_depr,
rustc_const_unstable
const_stability
});
impl<'a> HashStable<StableHashingContext<'a>>
@ -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 {

View File

@ -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);
}

View File

@ -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),
}

View File

@ -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

View File

@ -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);

View File

@ -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<SourceScope, SourceScopeLocalData>,
violations: Vec<UnsafetyViolation>,
source_info: SourceInfo,
@ -38,12 +39,16 @@ pub struct UnsafetyChecker<'a, 'tcx: 'a> {
}
impl<'a, 'gcx, 'tcx> UnsafetyChecker<'a, 'tcx> {
fn new(mir: &'a Mir<'tcx>,
source_scope_local_data: &'a IndexVec<SourceScope, SourceScopeLocalData>,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>) -> Self {
fn new(
min_const_fn: bool,
mir: &'a Mir<'tcx>,
source_scope_local_data: &'a IndexVec<SourceScope, SourceScopeLocalData>,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> Self {
Self {
mir,
min_const_fn,
source_scope_local_data,
violations: vec![],
source_info: SourceInfo {
@ -269,6 +274,15 @@ 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,

View File

@ -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;

View File

@ -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);

View File

@ -0,0 +1,378 @@
use rustc::hir::def_id::DefId;
use rustc::hir;
use rustc::mir::*;
use rustc::ty::{self, Predicate, TyCtxt};
use std::borrow::Cow;
use syntax_pos::Span;
mod helper {
pub struct IsMinConstFn(());
/// This should only ever be used *once* and then passed around as a token.
pub fn ensure_that_you_really_intended_to_create_an_instance_of_this() -> IsMinConstFn {
IsMinConstFn(())
}
}
use self::helper::*;
type McfResult = Result<IsMinConstFn, (Span, Cow<'static, str>)>;
pub fn is_min_const_fn(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId,
mir: &'a Mir<'tcx>,
) -> McfResult {
let mut current = def_id;
loop {
let predicates = tcx.predicates_of(current);
for predicate in &predicates.predicates {
match predicate {
| Predicate::RegionOutlives(_)
| Predicate::TypeOutlives(_)
| Predicate::WellFormed(_)
| Predicate::ConstEvaluatable(..) => continue,
| Predicate::ObjectSafe(_) => {
bug!("object safe predicate on function: {:#?}", predicate)
}
Predicate::ClosureKind(..) => {
bug!("closure kind predicate on function: {:#?}", predicate)
}
Predicate::Subtype(_) => bug!("subtype predicate on function: {:#?}", predicate),
Predicate::Projection(_) => {
let span = tcx.def_span(current);
// we'll hit a `Predicate::Trait` later which will report an error
tcx.sess
.delay_span_bug(span, "projection without trait bound");
continue;
}
Predicate::Trait(pred) => {
if Some(pred.def_id()) == tcx.lang_items().sized_trait() {
continue;
}
match pred.skip_binder().self_ty().sty {
ty::Param(ref p) => {
let generics = tcx.generics_of(current);
let def = generics.type_param(p, tcx);
let span = tcx.def_span(def.def_id);
return Err((
span,
"trait bounds other than `Sized` \
on const fn parameters are unstable"
.into(),
));
}
// other kinds of bounds are either tautologies
// or cause errors in other passes
_ => continue,
}
}
}
}
match predicates.parent {
Some(parent) => current = parent,
None => break,
}
}
let mut token = ensure_that_you_really_intended_to_create_an_instance_of_this();
for local in mir.vars_iter() {
return Err((
mir.local_decls[local].source_info.span,
"local variables in const fn are unstable".into(),
));
}
for local in &mir.local_decls {
token = check_ty(tcx, local.ty, local.source_info.span, token)?;
}
// impl trait is gone in MIR, so check the return type manually
token = check_ty(
tcx,
tcx.fn_sig(def_id).output().skip_binder(),
mir.local_decls.iter().next().unwrap().source_info.span,
token,
)?;
for bb in mir.basic_blocks() {
token = check_terminator(tcx, mir, bb.terminator(), token)?;
for stmt in &bb.statements {
token = check_statement(tcx, mir, stmt, token)?;
}
}
Ok(token)
}
fn check_ty(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
ty: ty::Ty<'tcx>,
span: Span,
token: IsMinConstFn,
) -> McfResult {
for ty in ty.walk() {
match ty.sty {
ty::Ref(_, _, hir::Mutability::MutMutable) => return Err((
span,
"mutable references in const fn are unstable".into(),
)),
ty::Anon(..) => return Err((span, "`impl Trait` in const fn is unstable".into())),
ty::FnPtr(..) => {
return Err((span, "function pointers in const fn are unstable".into()))
}
ty::Dynamic(preds, _) => {
for pred in preds.iter() {
match pred.skip_binder() {
| ty::ExistentialPredicate::AutoTrait(_)
| ty::ExistentialPredicate::Projection(_) => {
return Err((
span,
"trait bounds other than `Sized` \
on const fn parameters are unstable"
.into(),
))
}
ty::ExistentialPredicate::Trait(trait_ref) => {
if Some(trait_ref.def_id) != tcx.lang_items().sized_trait() {
return Err((
span,
"trait bounds other than `Sized` \
on const fn parameters are unstable"
.into(),
));
}
}
}
}
}
_ => {}
}
}
Ok(token)
}
fn check_rvalue(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
mir: &'a Mir<'tcx>,
rvalue: &Rvalue<'tcx>,
span: Span,
token: IsMinConstFn,
) -> McfResult {
match rvalue {
Rvalue::Repeat(operand, _) | Rvalue::Use(operand) => {
check_operand(tcx, mir, operand, span, token)
}
Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) => {
check_place(tcx, mir, place, span, token, PlaceMode::Read)
}
Rvalue::Cast(_, operand, cast_ty) => {
use rustc::ty::cast::CastTy;
let cast_in = CastTy::from_ty(operand.ty(mir, tcx)).expect("bad input type for cast");
let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
match (cast_in, cast_out) {
(CastTy::Ptr(_), CastTy::Int(_)) | (CastTy::FnPtr, CastTy::Int(_)) => Err((
span,
"casting pointers to ints is unstable in const fn".into(),
)),
(CastTy::RPtr(_), CastTy::Float) => bug!(),
(CastTy::RPtr(_), CastTy::Int(_)) => bug!(),
(CastTy::Ptr(_), CastTy::RPtr(_)) => bug!(),
_ => check_operand(tcx, mir, operand, span, token),
}
}
// binops are fine on integers
Rvalue::BinaryOp(_, lhs, rhs) | Rvalue::CheckedBinaryOp(_, lhs, rhs) => {
let token = check_operand(tcx, mir, lhs, span, token)?;
let token = check_operand(tcx, mir, rhs, span, token)?;
let ty = lhs.ty(mir, tcx);
if ty.is_integral() || ty.is_bool() || ty.is_char() {
Ok(token)
} else {
Err((
span,
"only int, `bool` and `char` operations are stable in const fn".into(),
))
}
}
// checked by regular const fn checks
Rvalue::NullaryOp(..) => Ok(token),
Rvalue::UnaryOp(_, operand) => {
let ty = operand.ty(mir, tcx);
if ty.is_integral() || ty.is_bool() {
check_operand(tcx, mir, operand, span, token)
} else {
Err((
span,
"only int and `bool` operations are stable in const fn".into(),
))
}
}
Rvalue::Aggregate(_, operands) => {
let mut token = token;
for operand in operands {
token = check_operand(tcx, mir, operand, span, token)?;
}
Ok(token)
}
}
}
enum PlaceMode {
Assign,
Read,
}
fn check_statement(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
mir: &'a Mir<'tcx>,
statement: &Statement<'tcx>,
token: IsMinConstFn,
) -> McfResult {
let span = statement.source_info.span;
match &statement.kind {
StatementKind::Assign(place, rval) => {
let token = check_place(tcx, mir, place, span, token, PlaceMode::Assign)?;
check_rvalue(tcx, mir, rval, span, token)
}
StatementKind::ReadForMatch(_) => Err((span, "match in const fn is unstable".into())),
// just an assignment
StatementKind::SetDiscriminant { .. } => Ok(token),
| StatementKind::InlineAsm { .. } => {
Err((span, "cannot use inline assembly in const fn".into()))
}
// These are all NOPs
| StatementKind::StorageLive(_)
| StatementKind::StorageDead(_)
| StatementKind::Validate(..)
| StatementKind::EndRegion(_)
| StatementKind::UserAssertTy(..)
| StatementKind::Nop => Ok(token),
}
}
fn check_operand(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
mir: &'a Mir<'tcx>,
operand: &Operand<'tcx>,
span: Span,
token: IsMinConstFn,
) -> McfResult {
match operand {
Operand::Move(place) | Operand::Copy(place) => {
check_place(tcx, mir, place, span, token, PlaceMode::Read)
}
Operand::Constant(_) => Ok(token),
}
}
fn check_place(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
mir: &'a Mir<'tcx>,
place: &Place<'tcx>,
span: Span,
token: IsMinConstFn,
mode: PlaceMode,
) -> McfResult {
match place {
Place::Local(l) => match mode {
PlaceMode::Assign => match mir.local_kind(*l) {
LocalKind::Temp | LocalKind::ReturnPointer => Ok(token),
LocalKind::Arg | LocalKind::Var => {
Err((span, "assignments in const fn are unstable".into()))
}
},
PlaceMode::Read => Ok(token),
},
// promoteds are always fine, they are essentially constants
Place::Promoted(_) => Ok(token),
Place::Static(_) => Err((span, "cannot access `static` items in const fn".into())),
Place::Projection(proj) => {
match proj.elem {
| ProjectionElem::Deref | ProjectionElem::Field(..) | ProjectionElem::Index(_) => {
check_place(tcx, mir, &proj.base, span, token, mode)
}
// slice patterns are unstable
| ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {
return Err((span, "slice patterns in const fn are unstable".into()))
}
| ProjectionElem::Downcast(..) => {
Err((span, "`match` or `if let` in `const fn` is unstable".into()))
}
}
}
}
}
fn check_terminator(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
mir: &'a Mir<'tcx>,
terminator: &Terminator<'tcx>,
token: IsMinConstFn,
) -> McfResult {
let span = terminator.source_info.span;
match &terminator.kind {
| TerminatorKind::Goto { .. }
| TerminatorKind::Return
| TerminatorKind::Resume => Ok(token),
TerminatorKind::Drop { location, .. } => {
check_place(tcx, mir, location, span, token, PlaceMode::Read)
}
TerminatorKind::DropAndReplace { location, value, .. } => {
let token = check_place(tcx, mir, location, span, token, PlaceMode::Read)?;
check_operand(tcx, mir, value, span, token)
},
TerminatorKind::SwitchInt { .. } => Err((
span,
"`if`, `match`, `&&` and `||` are not stable in const fn".into(),
)),
| TerminatorKind::Abort | TerminatorKind::Unreachable => {
Err((span, "const fn with unreachable code is not stable".into()))
}
| TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => {
Err((span, "const fn generators are unstable".into()))
}
TerminatorKind::Call {
func,
args,
destination: _,
cleanup: _,
} => {
let fn_ty = func.ty(mir, tcx);
if let ty::FnDef(def_id, _) = fn_ty.sty {
if tcx.is_min_const_fn(def_id) {
let mut token = check_operand(tcx, mir, func, span, token)?;
for arg in args {
token = check_operand(tcx, mir, arg, span, token)?;
}
Ok(token)
} else {
Err((
span,
"can only call other `min_const_fn` within a `min_const_fn`".into(),
))
}
} else {
Err((span, "can only call other const fns within const fn".into()))
}
}
TerminatorKind::Assert {
cond,
expected: _,
msg: _,
target: _,
cleanup: _,
} => check_operand(tcx, mir, cond, span, token),
| TerminatorKind::FalseEdges { .. } | TerminatorKind::FalseUnwind { .. } => span_bug!(
terminator.source_info.span,
"min_const_fn encountered `{:#?}`",
terminator
),
}
}

View File

@ -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,

View File

@ -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<Ty<'tcx>>,
output: Ty<'tcx>) {
fn equate_intrinsic_type<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
it: &hir::ForeignItem,
n_tps: usize,
abi: Abi,
safety: hir::Unsafety,
inputs: Vec<Ty<'tcx>>,
output: Ty<'tcx>,
) {
let def_id = tcx.hir.local_def_id(it.id);
match it.node {
@ -65,7 +68,7 @@ fn equate_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
inputs.into_iter(),
output,
false,
hir::Unsafety::Unsafe,
safety,
abi
)));
let cause = ObligationCause::new(it.span, it.id, ObligationCauseCode::IntrinsicType);
@ -78,7 +81,7 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
it: &hir::ForeignItem) {
let param = |n| tcx.mk_ty_param(n, Symbol::intern(&format!("P{}", n)).as_interned_str());
let name = it.name.as_str();
let (n_tps, inputs, output) = if name.starts_with("atomic_") {
let (n_tps, inputs, output, unsafety) = if name.starts_with("atomic_") {
let split : Vec<&str> = name.split('_').collect();
assert!(split.len() >= 2, "Atomic intrinsic not correct format");
@ -109,10 +112,14 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
return;
}
};
(n_tps, inputs, output)
(n_tps, inputs, output, hir::Unsafety::Unsafe)
} else if &name[..] == "abort" || &name[..] == "unreachable" {
(0, Vec::new(), tcx.types.never)
(0, Vec::new(), tcx.types.never, hir::Unsafety::Unsafe)
} else {
let unsafety = match &name[..] {
"size_of" | "min_align_of" => hir::Unsafety::Normal,
_ => hir::Unsafety::Unsafe,
};
let (n_tps, inputs, output) = match &name[..] {
"breakpoint" => (0, Vec::new(), tcx.mk_nil()),
"size_of" |
@ -327,9 +334,9 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
return;
}
};
(n_tps, inputs, output)
(n_tps, inputs, output, unsafety)
};
equate_intrinsic_type(tcx, it, n_tps, Abi::RustIntrinsic, inputs, output)
equate_intrinsic_type(tcx, it, n_tps, Abi::RustIntrinsic, unsafety, inputs, output)
}
/// Type-check `extern "platform-intrinsic" { ... }` functions.
@ -439,7 +446,7 @@ pub fn check_platform_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
};
equate_intrinsic_type(tcx, it, n_tps, Abi::PlatformIntrinsic,
equate_intrinsic_type(tcx, it, n_tps, Abi::PlatformIntrinsic, hir::Unsafety::Unsafe,
inputs, output)
}

View File

@ -1981,12 +1981,15 @@ fn compute_sig_of_foreign_fn_decl<'a, 'tcx>(
decl: &hir::FnDecl,
abi: abi::Abi,
) -> ty::PolyFnSig<'tcx> {
let fty = AstConv::ty_of_fn(
&ItemCtxt::new(tcx, def_id),
hir::Unsafety::Unsafe,
abi,
decl,
);
let unsafety = if abi == abi::Abi::RustIntrinsic {
match &*tcx.item_name(def_id).as_str() {
"size_of" | "min_align_of" => hir::Unsafety::Normal,
_ => hir::Unsafety::Unsafe,
}
} else {
hir::Unsafety::Unsafe
};
let fty = AstConv::ty_of_fn(&ItemCtxt::new(tcx, def_id), unsafety, abi, decl);
// feature gate SIMD types in FFI, since I (huonw) am not sure the
// ABIs are handled at all correctly.

View File

@ -18,7 +18,6 @@ pub struct Lazy<T> {
// We never call `lock.init()`, so it is UB to attempt to acquire this mutex reentrantly!
lock: Mutex,
ptr: Cell<*mut Arc<T>>,
init: fn() -> Arc<T>,
}
#[inline]
@ -26,33 +25,32 @@ const fn done<T>() -> *mut Arc<T> { 1_usize as *mut _ }
unsafe impl<T> Sync for Lazy<T> {}
impl<T: Send + Sync + 'static> Lazy<T> {
/// Safety: `init` must not call `get` on the variable that is being
/// initialized.
pub const unsafe fn new(init: fn() -> Arc<T>) -> Lazy<T> {
impl<T> Lazy<T> {
pub const fn new() -> Lazy<T> {
Lazy {
lock: Mutex::new(),
ptr: Cell::new(ptr::null_mut()),
init,
}
}
}
pub fn get(&'static self) -> Option<Arc<T>> {
unsafe {
let _guard = self.lock.lock();
let ptr = self.ptr.get();
if ptr.is_null() {
Some(self.init())
} else if ptr == done() {
None
} else {
Some((*ptr).clone())
}
impl<T: Send + Sync + 'static> Lazy<T> {
/// Safety: `init` must not call `get` on the variable that is being
/// initialized.
pub unsafe fn get(&'static self, init: fn() -> Arc<T>) -> Option<Arc<T>> {
let _guard = self.lock.lock();
let ptr = self.ptr.get();
if ptr.is_null() {
Some(self.init(init))
} else if ptr == done() {
None
} else {
Some((*ptr).clone())
}
}
// Must only be called with `lock` held
unsafe fn init(&'static self) -> Arc<T> {
unsafe fn init(&'static self, init: fn() -> Arc<T>) -> Arc<T> {
// If we successfully register an at exit handler, then we cache the
// `Arc` allocation in our own internal box (it will get deallocated by
// the at exit handler). Otherwise we just return the freshly allocated
@ -66,8 +64,8 @@ impl<T: Send + Sync + 'static> Lazy<T> {
});
// This could reentrantly call `init` again, which is a problem
// because our `lock` allows reentrancy!
// That's why `new` is unsafe and requires the caller to ensure no reentrancy happens.
let ret = (self.init)();
// That's why `get` is unsafe and requires the caller to ensure no reentrancy happens.
let ret = init();
if registered.is_ok() {
self.ptr.set(Box::into_raw(Box::new(ret.clone())));
}

View File

@ -197,9 +197,11 @@ pub struct StdinLock<'a> {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn stdin() -> Stdin {
static INSTANCE: Lazy<Mutex<BufReader<Maybe<StdinRaw>>>> = unsafe { Lazy::new(stdin_init) };
static INSTANCE: Lazy<Mutex<BufReader<Maybe<StdinRaw>>>> = Lazy::new();
return Stdin {
inner: INSTANCE.get().expect("cannot access stdin during shutdown"),
inner: unsafe {
INSTANCE.get(stdin_init).expect("cannot access stdin during shutdown")
},
};
fn stdin_init() -> Arc<Mutex<BufReader<Maybe<StdinRaw>>>> {
@ -396,10 +398,11 @@ pub struct StdoutLock<'a> {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn stdout() -> Stdout {
static INSTANCE: Lazy<ReentrantMutex<RefCell<LineWriter<Maybe<StdoutRaw>>>>>
= unsafe { Lazy::new(stdout_init) };
static INSTANCE: Lazy<ReentrantMutex<RefCell<LineWriter<Maybe<StdoutRaw>>>>> = Lazy::new();
return Stdout {
inner: INSTANCE.get().expect("cannot access stdout during shutdown"),
inner: unsafe {
INSTANCE.get(stdout_init).expect("cannot access stdout during shutdown")
},
};
fn stdout_init() -> Arc<ReentrantMutex<RefCell<LineWriter<Maybe<StdoutRaw>>>>> {
@ -533,10 +536,11 @@ pub struct StderrLock<'a> {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn stderr() -> Stderr {
static INSTANCE: Lazy<ReentrantMutex<RefCell<Maybe<StderrRaw>>>> =
unsafe { Lazy::new(stderr_init) };
static INSTANCE: Lazy<ReentrantMutex<RefCell<Maybe<StderrRaw>>>> = Lazy::new();
return Stderr {
inner: INSTANCE.get().expect("cannot access stderr during shutdown"),
inner: unsafe {
INSTANCE.get(stderr_init).expect("cannot access stderr during shutdown")
},
};
fn stderr_init() -> Arc<ReentrantMutex<RefCell<Maybe<StderrRaw>>>> {

View File

@ -107,7 +107,11 @@ pub struct Stability {
pub level: StabilityLevel,
pub feature: Symbol,
pub rustc_depr: Option<RustcDeprecation>,
pub rustc_const_unstable: Option<RustcConstUnstable>,
/// `None` means the function is stable but needs to be allowed by the
/// `min_const_fn` feature
/// `Some` contains the feature gate required to be able to use the function
/// as const fn
pub const_stability: Option<Symbol>,
}
/// The available stability levels.
@ -141,11 +145,6 @@ pub struct RustcDeprecation {
pub reason: Symbol,
}
#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Eq, Hash)]
pub struct RustcConstUnstable {
pub feature: Symbol,
}
/// Check if `attrs` contains an attribute like `#![feature(feature_name)]`.
/// This will not perform any "sanity checks" on the form of the attributes.
pub fn contains_feature_attr(attrs: &[Attribute], feature_name: &str) -> bool {
@ -176,7 +175,7 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler,
let mut stab: Option<Stability> = None;
let mut rustc_depr: Option<RustcDeprecation> = None;
let mut rustc_const_unstable: Option<RustcConstUnstable> = None;
let mut rustc_const_unstable: Option<Symbol> = None;
'outer: for attr in attrs_iter {
if ![
@ -191,6 +190,7 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler,
mark_used(attr);
let meta = attr.meta();
// attributes with data
if let Some(MetaItem { node: MetaItemKind::List(ref metas), .. }) = meta {
let meta = meta.as_ref().unwrap();
let get = |meta: &MetaItem, item: &mut Option<Symbol>| {
@ -272,9 +272,7 @@ 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 \

View File

@ -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::*;

View File

@ -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(..) => {

View File

@ -10,7 +10,7 @@
// ignore-emscripten
// compile-flags: -Z lower_128bit_ops=yes -C debug_assertions=no
// compile-flags: -Z lower_128bit_ops=yes -C debug_assertions=no -O
#![feature(const_fn)]
@ -63,103 +63,65 @@ fn main() {
// END RUST SOURCE
// START rustc.const_signed.Lower128Bit.after.mir
// _8 = _1;
// _9 = const compiler_builtins::int::addsub::rust_i128_addo(move _8, const 1i128) -> bb10;
// ...
// _7 = move (_9.0: i128);
// ...
// _10 = const compiler_builtins::int::addsub::rust_i128_subo(move _7, const 2i128) -> bb11;
// ...
// _6 = move (_10.0: i128);
// ...
// _11 = const compiler_builtins::int::mul::rust_i128_mulo(move _6, const 3i128) -> bb12;
// ...
// _5 = move (_11.0: i128);
// ...
// _12 = Eq(const 4i128, const 0i128);
// assert(!move _12, "attempt to divide by zero") -> bb4;
// ...
// _13 = Eq(const 4i128, const -1i128);
// _14 = Eq(_5, const -170141183460469231731687303715884105728i128);
// _15 = BitAnd(move _13, move _14);
// assert(!move _15, "attempt to divide with overflow") -> bb5;
// ...
// _4 = const compiler_builtins::int::sdiv::rust_i128_div(move _5, const 4i128) -> bb13;
// ...
// _17 = Eq(const 5i128, const -1i128);
// _18 = Eq(_4, const -170141183460469231731687303715884105728i128);
// _19 = BitAnd(move _17, move _18);
// assert(!move _19, "attempt to calculate the remainder with overflow") -> bb7;
// ...
// _3 = const compiler_builtins::int::sdiv::rust_i128_rem(move _4, const 5i128) -> bb15;
// ...
// _2 = move (_20.0: i128);
// ...
// _23 = const 7i32 as u128 (Misc);
// _21 = const compiler_builtins::int::shift::rust_i128_shro(move _2, move _23) -> bb16;
// ...
// _0 = move (_21.0: i128);
// ...
// assert(!move (_9.1: bool), "attempt to add with overflow") -> bb1;
// ...
// assert(!move (_10.1: bool), "attempt to subtract with overflow") -> bb2;
// ...
// assert(!move (_11.1: bool), "attempt to multiply with overflow") -> bb3;
// ...
// _16 = Eq(const 5i128, const 0i128);
// assert(!move _16, "attempt to calculate the remainder with a divisor of zero") -> bb6;
// ...
// assert(!move (_20.1: bool), "attempt to shift left with overflow") -> bb8;
// ...
// _22 = const 6i32 as u128 (Misc);
// _20 = const compiler_builtins::int::shift::rust_i128_shlo(move _3, move _22) -> bb14;
// ...
// assert(!move (_21.1: bool), "attempt to shift right with overflow") -> bb9;
// _7 = const compiler_builtins::int::addsub::rust_i128_add(move _8, const 1i128) -> bb7;
// ...
// _10 = Eq(const 4i128, const -1i128);
// _11 = Eq(_5, const -170141183460469231731687303715884105728i128);
// _12 = BitAnd(move _10, move _11);
// assert(!move _12, "attempt to divide with overflow") -> bb2;
// ...
// _4 = const compiler_builtins::int::sdiv::rust_i128_div(move _5, const 4i128) -> bb8;
// ...
// _14 = Eq(const 5i128, const -1i128);
// _15 = Eq(_4, const -170141183460469231731687303715884105728i128);
// _16 = BitAnd(move _14, move _15);
// assert(!move _16, "attempt to calculate the remainder with overflow") -> bb4;
// ...
// _3 = const compiler_builtins::int::sdiv::rust_i128_rem(move _4, const 5i128) -> bb11;
// ...
// _9 = Eq(const 4i128, const 0i128);
// assert(!move _9, "attempt to divide by zero") -> bb1;
// ...
// _5 = const compiler_builtins::int::mul::rust_i128_mul(move _6, const 3i128) -> bb5;
// ...
// _6 = const compiler_builtins::int::addsub::rust_i128_sub(move _7, const 2i128) -> bb6;
// ...
// _13 = Eq(const 5i128, const 0i128);
// assert(!move _13, "attempt to calculate the remainder with a divisor of zero") -> bb3;
// ...
// _17 = const 7i32 as u32 (Misc);
// _0 = const compiler_builtins::int::shift::rust_i128_shr(move _2, move _17) -> bb9;
// ...
// _18 = const 6i32 as u32 (Misc);
// _2 = const compiler_builtins::int::shift::rust_i128_shl(move _3, move _18) -> bb10;
// END rustc.const_signed.Lower128Bit.after.mir
// START rustc.const_unsigned.Lower128Bit.after.mir
// _8 = _1;
// _9 = const compiler_builtins::int::addsub::rust_u128_addo(move _8, const 1u128) -> bb8;
// ...
// _7 = move (_9.0: u128);
// ...
// _10 = const compiler_builtins::int::addsub::rust_u128_subo(move _7, const 2u128) -> bb9;
// ...
// _6 = move (_10.0: u128);
// ...
// _11 = const compiler_builtins::int::mul::rust_u128_mulo(move _6, const 3u128) -> bb10;
// ...
// _5 = move (_11.0: u128);
// ...
// _12 = Eq(const 4u128, const 0u128);
// assert(!move _12, "attempt to divide by zero") -> bb4;
// ...
// _4 = const compiler_builtins::int::udiv::rust_u128_div(move _5, const 4u128) -> bb11;
// ...
// _3 = const compiler_builtins::int::udiv::rust_u128_rem(move _4, const 5u128) -> bb13;
// ...
// _2 = move (_14.0: u128);
// ...
// _17 = const 7i32 as u128 (Misc);
// _15 = const compiler_builtins::int::shift::rust_u128_shro(move _2, move _17) -> bb14;
// ...
// _0 = move (_15.0: u128);
// ...
// assert(!move (_9.1: bool), "attempt to add with overflow") -> bb1;
// ...
// assert(!move (_10.1: bool), "attempt to subtract with overflow") -> bb2;
// ...
// assert(!move (_11.1: bool), "attempt to multiply with overflow") -> bb3;
// ...
// _13 = Eq(const 5u128, const 0u128);
// assert(!move _13, "attempt to calculate the remainder with a divisor of zero") -> bb5;
// ...
// assert(!move (_14.1: bool), "attempt to shift left with overflow") -> bb6;
// ...
// _16 = const 6i32 as u128 (Misc);
// _14 = const compiler_builtins::int::shift::rust_u128_shlo(move _3, move _16) -> bb12;
// ...
// assert(!move (_15.1: bool), "attempt to shift right with overflow") -> bb7;
// _8 = _1;
// _7 = const compiler_builtins::int::addsub::rust_u128_add(move _8, const 1u128) -> bb5;
// ...
// _4 = const compiler_builtins::int::udiv::rust_u128_div(move _5, const 4u128) -> bb6;
// ...
// _3 = const compiler_builtins::int::udiv::rust_u128_rem(move _4, const 5u128) -> bb9;
// ...
// _9 = Eq(const 4u128, const 0u128);
// assert(!move _9, "attempt to divide by zero") -> bb1;
// ...
// _5 = const compiler_builtins::int::mul::rust_u128_mul(move _6, const 3u128) -> bb3;
// ...
// _6 = const compiler_builtins::int::addsub::rust_u128_sub(move _7, const 2u128) -> bb4;
// ...
// _10 = Eq(const 5u128, const 0u128);
// assert(!move _10, "attempt to calculate the remainder with a divisor of zero") -> bb2;
// ...
// return;
// ...
// _11 = const 7i32 as u32 (Misc);
// _0 = const compiler_builtins::int::shift::rust_u128_shr(move _2, move _11) -> bb7;
// ...
// _12 = const 6i32 as u32 (Misc);
// _2 = const compiler_builtins::int::shift::rust_u128_shl(move _3, move _12) -> bb8;
// END rustc.const_unsigned.Lower128Bit.after.mir
// START rustc.test_signed.Lower128Bit.after.mir

View File

@ -11,6 +11,8 @@
// ignore-wasm32
// ignore-emscripten
// compile-flags: -C debug_assertions=yes
#![feature(const_fn, libc)]
#![allow(const_err)]
@ -19,7 +21,7 @@ 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() {

View File

@ -4,14 +4,14 @@ note: ...which requires normalizing `ParamEnvAnd { param_env: ParamEnv { caller_
note: ...which requires const-evaluating `Foo::bytes::{{constant}}`...
--> $SRC_DIR/libcore/mem.rs:LL:COL
|
LL | unsafe { intrinsics::size_of::<T>() }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | intrinsics::size_of::<T>()
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...which again requires computing layout of `Foo`, completing the cycle
note: cycle used when const-evaluating `Foo::bytes::{{constant}}`
--> $SRC_DIR/libcore/mem.rs:LL:COL
|
LL | unsafe { intrinsics::size_of::<T>() }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | intrinsics::size_of::<T>()
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error

View File

@ -0,0 +1,224 @@
error[E0493]: destructors cannot be evaluated at compile-time
--> $DIR/min_const_fn.rs:49:25
|
LL | const fn into_inner(self) -> T { self.0 } //~ destructors cannot be evaluated
| ^^^^ constant functions cannot evaluate destructors
error: mutable references in const fn are unstable
--> $DIR/min_const_fn.rs:51:5
|
LL | const fn get_mut(&mut self) -> &mut T { &mut self.0 }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0493]: destructors cannot be evaluated at compile-time
--> $DIR/min_const_fn.rs:56:28
|
LL | const fn into_inner_lt(self) -> T { self.0 } //~ destructors cannot be evaluated
| ^^^^ constant functions cannot evaluate destructors
error: mutable references in const fn are unstable
--> $DIR/min_const_fn.rs:58:5
|
LL | const fn get_mut_lt(&'a mut self) -> &mut T { &mut self.0 }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0493]: destructors cannot be evaluated at compile-time
--> $DIR/min_const_fn.rs:63:27
|
LL | const fn into_inner_s(self) -> T { self.0 } //~ ERROR destructors
| ^^^^ constant functions cannot evaluate destructors
error: mutable references in const fn are unstable
--> $DIR/min_const_fn.rs:65:5
|
LL | const fn get_mut_s(&mut self) -> &mut T { &mut self.0 }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: mutable references in const fn are unstable
--> $DIR/min_const_fn.rs:70:5
|
LL | const fn get_mut_sq(&mut self) -> &mut T { &mut self.0 }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: trait bounds other than `Sized` on const fn parameters are unstable
--> $DIR/min_const_fn.rs:88:16
|
LL | const fn foo11<T: std::fmt::Display>(t: T) -> T { t }
| ^
error: trait bounds other than `Sized` on const fn parameters are unstable
--> $DIR/min_const_fn.rs:90:18
|
LL | const fn foo11_2<T: Send>(t: T) -> T { t }
| ^
error: only int, `bool` and `char` operations are stable in const fn
--> $DIR/min_const_fn.rs:92:33
|
LL | const fn foo19(f: f32) -> f32 { f * 2.0 }
| ^^^^^^^
error: only int, `bool` and `char` operations are stable in const fn
--> $DIR/min_const_fn.rs:94:35
|
LL | const fn foo19_2(f: f32) -> f32 { 2.0 - f }
| ^^^^^^^
error: only int and `bool` operations are stable in const fn
--> $DIR/min_const_fn.rs:96:35
|
LL | const fn foo19_3(f: f32) -> f32 { -f }
| ^^
error: only int, `bool` and `char` operations are stable in const fn
--> $DIR/min_const_fn.rs:98:43
|
LL | const fn foo19_4(f: f32, g: f32) -> f32 { f / g }
| ^^^^^
error: cannot access `static` items in const fn
--> $DIR/min_const_fn.rs:102:27
|
LL | const fn foo25() -> u32 { BAR } //~ ERROR cannot access `static` items in const fn
| ^^^
error: cannot access `static` items in const fn
--> $DIR/min_const_fn.rs:103:36
|
LL | const fn foo26() -> &'static u32 { &BAR } //~ ERROR cannot access `static` items
| ^^^^
error: casting pointers to ints is unstable in const fn
--> $DIR/min_const_fn.rs:104:42
|
LL | const fn foo30(x: *const u32) -> usize { x as usize }
| ^^^^^^^^^^
error: casting pointers to ints is unstable in const fn
--> $DIR/min_const_fn.rs:106:42
|
LL | const fn foo30_2(x: *mut u32) -> usize { x as usize }
| ^^^^^^^^^^
error: `if`, `match`, `&&` and `||` are not stable in const fn
--> $DIR/min_const_fn.rs:108:38
|
LL | const fn foo30_4(b: bool) -> usize { if b { 1 } else { 42 } }
| ^^^^^^^^^^^^^^^^^^^^^^
error: `if`, `match`, `&&` and `||` are not stable in const fn
--> $DIR/min_const_fn.rs:110:29
|
LL | const fn foo30_5(b: bool) { while b { } } //~ ERROR not stable in const fn
| ^^^^^^^^^^^
error: local variables in const fn are unstable
--> $DIR/min_const_fn.rs:111:34
|
LL | const fn foo30_6() -> bool { let x = true; x } //~ ERROR local variables in const fn are unstable
| ^
error: `if`, `match`, `&&` and `||` are not stable in const fn
--> $DIR/min_const_fn.rs:112:44
|
LL | const fn foo36(a: bool, b: bool) -> bool { a && b }
| ^^^^^^
error: `if`, `match`, `&&` and `||` are not stable in const fn
--> $DIR/min_const_fn.rs:114:44
|
LL | const fn foo37(a: bool, b: bool) -> bool { a || b }
| ^^^^^^
error: mutable references in const fn are unstable
--> $DIR/min_const_fn.rs:116:14
|
LL | const fn inc(x: &mut i32) { *x += 1 }
| ^
error: trait bounds other than `Sized` on const fn parameters are unstable
--> $DIR/min_const_fn.rs:121:6
|
LL | impl<T: std::fmt::Debug> Foo<T> {
| ^
error: trait bounds other than `Sized` on const fn parameters are unstable
--> $DIR/min_const_fn.rs:126:6
|
LL | impl<T: std::fmt::Debug + Sized> Foo<T> {
| ^
error: trait bounds other than `Sized` on const fn parameters are unstable
--> $DIR/min_const_fn.rs:131:6
|
LL | impl<T: Sync + Sized> Foo<T> {
| ^
error: `impl Trait` in const fn is unstable
--> $DIR/min_const_fn.rs:137:1
|
LL | const fn no_rpit2() -> AlanTuring<impl std::fmt::Debug> { AlanTuring(0) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: trait bounds other than `Sized` on const fn parameters are unstable
--> $DIR/min_const_fn.rs:139:34
|
LL | const fn no_apit2(_x: AlanTuring<impl std::fmt::Debug>) {}
| ^^^^^^^^^^^^^^^^^^^^
error: trait bounds other than `Sized` on const fn parameters are unstable
--> $DIR/min_const_fn.rs:141:22
|
LL | const fn no_apit(_x: impl std::fmt::Debug) {} //~ ERROR trait bounds other than `Sized`
| ^^^^^^^^^^^^^^^^^^^^
error: `impl Trait` in const fn is unstable
--> $DIR/min_const_fn.rs:142:1
|
LL | const fn no_rpit() -> impl std::fmt::Debug {} //~ ERROR `impl Trait` in const fn is unstable
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: trait bounds other than `Sized` on const fn parameters are unstable
--> $DIR/min_const_fn.rs:143:23
|
LL | const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {} //~ ERROR trait bounds other than `Sized`
| ^^
error: trait bounds other than `Sized` on const fn parameters are unstable
--> $DIR/min_const_fn.rs:144:1
|
LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0597]: borrowed value does not live long enough
--> $DIR/min_const_fn.rs:144:64
|
LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
| ^^ - temporary value only lives until here
| |
| temporary value does not live long enough
|
= note: borrowed value must be valid for the static lifetime...
error: trait bounds other than `Sized` on const fn parameters are unstable
--> $DIR/min_const_fn.rs:149:41
|
LL | const fn really_no_traits_i_mean_it() { (&() as &std::fmt::Debug, ()).1 }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: function pointers in const fn are unstable
--> $DIR/min_const_fn.rs:152:21
|
LL | const fn no_fn_ptrs(_x: fn()) {}
| ^^
error: function pointers in const fn are unstable
--> $DIR/min_const_fn.rs:154:1
|
LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 36 previous errors
Some errors occurred: E0493, E0597.
For more information about an error, try `rustc --explain E0493`.

View File

@ -0,0 +1,156 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(min_const_fn)]
// ok
const fn foo1() {}
const fn foo2(x: i32) -> i32 { x }
const fn foo3<T>(x: T) -> T { x }
const fn foo7() {
(
foo1(),
foo2(420),
foo3(69),
).0
}
const fn foo12<T: Sized>(t: T) -> T { t }
const fn foo13<T: ?Sized>(t: &T) -> &T { t }
const fn foo14<'a, T: 'a>(t: &'a T) -> &'a T { t }
const fn foo15<T>(t: T) -> T where T: Sized { t }
const fn foo15_2<T>(t: &T) -> &T where T: ?Sized { t }
const fn foo16(f: f32) -> f32 { f }
const fn foo17(f: f32) -> u32 { f as u32 }
const fn foo18(i: i32) -> i32 { i * 3 }
const fn foo20(b: bool) -> bool { !b }
const fn foo21<T, U>(t: T, u: U) -> (T, U) { (t, u) }
const fn foo22(s: &[u8], i: usize) -> u8 { s[i] }
const FOO: u32 = 42;
const fn foo23() -> u32 { FOO }
const fn foo24() -> &'static u32 { &FOO }
const fn foo27(x: &u32) -> u32 { *x }
const fn foo28(x: u32) -> u32 { *&x }
const fn foo29(x: u32) -> i32 { x as i32 }
const fn foo31(a: bool, b: bool) -> bool { a & b }
const fn foo32(a: bool, b: bool) -> bool { a | b }
const fn foo33(a: bool, b: bool) -> bool { a & b }
const fn foo34(a: bool, b: bool) -> bool { a | b }
const fn foo35(a: bool, b: bool) -> bool { a ^ b }
struct Foo<T: ?Sized>(T);
impl<T> Foo<T> {
const fn new(t: T) -> Self { Foo(t) }
const fn into_inner(self) -> T { self.0 } //~ destructors cannot be evaluated
const fn get(&self) -> &T { &self.0 }
const fn get_mut(&mut self) -> &mut T { &mut self.0 }
//~^ mutable references in const fn are unstable
}
impl<'a, T> Foo<T> {
const fn new_lt(t: T) -> Self { Foo(t) }
const fn into_inner_lt(self) -> T { self.0 } //~ destructors cannot be evaluated
const fn get_lt(&'a self) -> &T { &self.0 }
const fn get_mut_lt(&'a mut self) -> &mut T { &mut self.0 }
//~^ mutable references in const fn are unstable
}
impl<T: Sized> Foo<T> {
const fn new_s(t: T) -> Self { Foo(t) }
const fn into_inner_s(self) -> T { self.0 } //~ ERROR destructors
const fn get_s(&self) -> &T { &self.0 }
const fn get_mut_s(&mut self) -> &mut T { &mut self.0 }
//~^ mutable references in const fn are unstable
}
impl<T: ?Sized> Foo<T> {
const fn get_sq(&self) -> &T { &self.0 }
const fn get_mut_sq(&mut self) -> &mut T { &mut self.0 }
//~^ mutable references in const fn are unstable
}
const fn char_ops(c: char, d: char) -> bool { c == d }
const fn char_ops2(c: char, d: char) -> bool { c < d }
const fn char_ops3(c: char, d: char) -> bool { c != d }
const fn i32_ops(c: i32, d: i32) -> bool { c == d }
const fn i32_ops2(c: i32, d: i32) -> bool { c < d }
const fn i32_ops3(c: i32, d: i32) -> bool { c != d }
const fn i32_ops4(c: i32, d: i32) -> i32 { c + d }
const fn char_cast(u: u8) -> char { u as char }
const unsafe fn foo4() -> i32 { 42 }
const unsafe fn foo5<T>() -> *const T { 0 as *const T }
const unsafe fn foo6<T>() -> *mut T { 0 as *mut T }
// not ok
const fn foo11<T: std::fmt::Display>(t: T) -> T { t }
//~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable
const fn foo11_2<T: Send>(t: T) -> T { t }
//~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable
const fn foo19(f: f32) -> f32 { f * 2.0 }
//~^ ERROR only int, `bool` and `char` operations are stable in const fn
const fn foo19_2(f: f32) -> f32 { 2.0 - f }
//~^ ERROR only int, `bool` and `char` operations are stable in const fn
const fn foo19_3(f: f32) -> f32 { -f }
//~^ ERROR only int and `bool` operations are stable in const fn
const fn foo19_4(f: f32, g: f32) -> f32 { f / g }
//~^ ERROR only int, `bool` and `char` operations are stable in const fn
static BAR: u32 = 42;
const fn foo25() -> u32 { BAR } //~ ERROR cannot access `static` items in const fn
const fn foo26() -> &'static u32 { &BAR } //~ ERROR cannot access `static` items
const fn foo30(x: *const u32) -> usize { x as usize }
//~^ ERROR casting pointers to int
const fn foo30_2(x: *mut u32) -> usize { x as usize }
//~^ ERROR casting pointers to int
const fn foo30_4(b: bool) -> usize { if b { 1 } else { 42 } }
//~^ ERROR `if`, `match`, `&&` and `||` are not stable in const fn
const fn foo30_5(b: bool) { while b { } } //~ ERROR not stable in const fn
const fn foo30_6() -> bool { let x = true; x } //~ ERROR local variables in const fn are unstable
const fn foo36(a: bool, b: bool) -> bool { a && b }
//~^ ERROR `if`, `match`, `&&` and `||` are not stable in const fn
const fn foo37(a: bool, b: bool) -> bool { a || b }
//~^ ERROR `if`, `match`, `&&` and `||` are not stable in const fn
const fn inc(x: &mut i32) { *x += 1 }
//~^ ERROR mutable references in const fn are unstable
fn main() {}
impl<T: std::fmt::Debug> Foo<T> {
//~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable
const fn foo(&self) {}
}
impl<T: std::fmt::Debug + Sized> Foo<T> {
//~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable
const fn foo2(&self) {}
}
impl<T: Sync + Sized> Foo<T> {
//~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable
const fn foo3(&self) {}
}
struct AlanTuring<T>(T);
const fn no_rpit2() -> AlanTuring<impl std::fmt::Debug> { AlanTuring(0) }
//~^ ERROR `impl Trait` in const fn is unstable
const fn no_apit2(_x: AlanTuring<impl std::fmt::Debug>) {}
//~^ ERROR trait bounds other than `Sized`
const fn no_apit(_x: impl std::fmt::Debug) {} //~ ERROR trait bounds other than `Sized`
const fn no_rpit() -> impl std::fmt::Debug {} //~ ERROR `impl Trait` in const fn is unstable
const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {} //~ ERROR trait bounds other than `Sized`
const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
//~^ ERROR trait bounds other than `Sized`
const fn no_unsafe() { unsafe {} }
const fn really_no_traits_i_mean_it() { (&() as &std::fmt::Debug, ()).1 }
//~^ ERROR trait bounds other than `Sized`
const fn no_fn_ptrs(_x: fn()) {}
//~^ ERROR function pointers in const fn are unstable
const fn no_fn_ptrs2() -> fn() { fn foo() {} foo }
//~^ ERROR function pointers in const fn are unstable

View File

@ -0,0 +1,213 @@
error[E0493]: destructors cannot be evaluated at compile-time
--> $DIR/min_const_fn.rs:49:25
|
LL | const fn into_inner(self) -> T { self.0 } //~ destructors cannot be evaluated
| ^^^^ constant functions cannot evaluate destructors
error: mutable references in const fn are unstable
--> $DIR/min_const_fn.rs:51:5
|
LL | const fn get_mut(&mut self) -> &mut T { &mut self.0 }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0493]: destructors cannot be evaluated at compile-time
--> $DIR/min_const_fn.rs:56:28
|
LL | const fn into_inner_lt(self) -> T { self.0 } //~ destructors cannot be evaluated
| ^^^^ constant functions cannot evaluate destructors
error: mutable references in const fn are unstable
--> $DIR/min_const_fn.rs:58:5
|
LL | const fn get_mut_lt(&'a mut self) -> &mut T { &mut self.0 }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0493]: destructors cannot be evaluated at compile-time
--> $DIR/min_const_fn.rs:63:27
|
LL | const fn into_inner_s(self) -> T { self.0 } //~ ERROR destructors
| ^^^^ constant functions cannot evaluate destructors
error: mutable references in const fn are unstable
--> $DIR/min_const_fn.rs:65:5
|
LL | const fn get_mut_s(&mut self) -> &mut T { &mut self.0 }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: mutable references in const fn are unstable
--> $DIR/min_const_fn.rs:70:5
|
LL | const fn get_mut_sq(&mut self) -> &mut T { &mut self.0 }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: trait bounds other than `Sized` on const fn parameters are unstable
--> $DIR/min_const_fn.rs:88:16
|
LL | const fn foo11<T: std::fmt::Display>(t: T) -> T { t }
| ^
error: trait bounds other than `Sized` on const fn parameters are unstable
--> $DIR/min_const_fn.rs:90:18
|
LL | const fn foo11_2<T: Send>(t: T) -> T { t }
| ^
error: only int, `bool` and `char` operations are stable in const fn
--> $DIR/min_const_fn.rs:92:33
|
LL | const fn foo19(f: f32) -> f32 { f * 2.0 }
| ^^^^^^^
error: only int, `bool` and `char` operations are stable in const fn
--> $DIR/min_const_fn.rs:94:35
|
LL | const fn foo19_2(f: f32) -> f32 { 2.0 - f }
| ^^^^^^^
error: only int and `bool` operations are stable in const fn
--> $DIR/min_const_fn.rs:96:35
|
LL | const fn foo19_3(f: f32) -> f32 { -f }
| ^^
error: only int, `bool` and `char` operations are stable in const fn
--> $DIR/min_const_fn.rs:98:43
|
LL | const fn foo19_4(f: f32, g: f32) -> f32 { f / g }
| ^^^^^
error: cannot access `static` items in const fn
--> $DIR/min_const_fn.rs:102:27
|
LL | const fn foo25() -> u32 { BAR } //~ ERROR cannot access `static` items in const fn
| ^^^
error: cannot access `static` items in const fn
--> $DIR/min_const_fn.rs:103:36
|
LL | const fn foo26() -> &'static u32 { &BAR } //~ ERROR cannot access `static` items
| ^^^^
error: casting pointers to ints is unstable in const fn
--> $DIR/min_const_fn.rs:104:42
|
LL | const fn foo30(x: *const u32) -> usize { x as usize }
| ^^^^^^^^^^
error: casting pointers to ints is unstable in const fn
--> $DIR/min_const_fn.rs:106:42
|
LL | const fn foo30_2(x: *mut u32) -> usize { x as usize }
| ^^^^^^^^^^
error: `if`, `match`, `&&` and `||` are not stable in const fn
--> $DIR/min_const_fn.rs:108:38
|
LL | const fn foo30_4(b: bool) -> usize { if b { 1 } else { 42 } }
| ^^^^^^^^^^^^^^^^^^^^^^
error: `if`, `match`, `&&` and `||` are not stable in const fn
--> $DIR/min_const_fn.rs:110:29
|
LL | const fn foo30_5(b: bool) { while b { } } //~ ERROR not stable in const fn
| ^^^^^^^^^^^
error: local variables in const fn are unstable
--> $DIR/min_const_fn.rs:111:34
|
LL | const fn foo30_6() -> bool { let x = true; x } //~ ERROR local variables in const fn are unstable
| ^
error: `if`, `match`, `&&` and `||` are not stable in const fn
--> $DIR/min_const_fn.rs:112:44
|
LL | const fn foo36(a: bool, b: bool) -> bool { a && b }
| ^^^^^^
error: `if`, `match`, `&&` and `||` are not stable in const fn
--> $DIR/min_const_fn.rs:114:44
|
LL | const fn foo37(a: bool, b: bool) -> bool { a || b }
| ^^^^^^
error: mutable references in const fn are unstable
--> $DIR/min_const_fn.rs:116:14
|
LL | const fn inc(x: &mut i32) { *x += 1 }
| ^
error: trait bounds other than `Sized` on const fn parameters are unstable
--> $DIR/min_const_fn.rs:121:6
|
LL | impl<T: std::fmt::Debug> Foo<T> {
| ^
error: trait bounds other than `Sized` on const fn parameters are unstable
--> $DIR/min_const_fn.rs:126:6
|
LL | impl<T: std::fmt::Debug + Sized> Foo<T> {
| ^
error: trait bounds other than `Sized` on const fn parameters are unstable
--> $DIR/min_const_fn.rs:131:6
|
LL | impl<T: Sync + Sized> Foo<T> {
| ^
error: `impl Trait` in const fn is unstable
--> $DIR/min_const_fn.rs:137:1
|
LL | const fn no_rpit2() -> AlanTuring<impl std::fmt::Debug> { AlanTuring(0) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: trait bounds other than `Sized` on const fn parameters are unstable
--> $DIR/min_const_fn.rs:139:34
|
LL | const fn no_apit2(_x: AlanTuring<impl std::fmt::Debug>) {}
| ^^^^^^^^^^^^^^^^^^^^
error: trait bounds other than `Sized` on const fn parameters are unstable
--> $DIR/min_const_fn.rs:141:22
|
LL | const fn no_apit(_x: impl std::fmt::Debug) {} //~ ERROR trait bounds other than `Sized`
| ^^^^^^^^^^^^^^^^^^^^
error: `impl Trait` in const fn is unstable
--> $DIR/min_const_fn.rs:142:1
|
LL | const fn no_rpit() -> impl std::fmt::Debug {} //~ ERROR `impl Trait` in const fn is unstable
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: trait bounds other than `Sized` on const fn parameters are unstable
--> $DIR/min_const_fn.rs:143:23
|
LL | const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {} //~ ERROR trait bounds other than `Sized`
| ^^
error: trait bounds other than `Sized` on const fn parameters are unstable
--> $DIR/min_const_fn.rs:144:1
|
LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: trait bounds other than `Sized` on const fn parameters are unstable
--> $DIR/min_const_fn.rs:149:41
|
LL | const fn really_no_traits_i_mean_it() { (&() as &std::fmt::Debug, ()).1 }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: function pointers in const fn are unstable
--> $DIR/min_const_fn.rs:152:21
|
LL | const fn no_fn_ptrs(_x: fn()) {}
| ^^
error: function pointers in const fn are unstable
--> $DIR/min_const_fn.rs:154:1
|
LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 35 previous errors
For more information about this error, try `rustc --explain E0493`.

View File

@ -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`.

View File

@ -0,0 +1,27 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(min_const_fn)]
struct HasDyn {
field: &'static dyn std::fmt::Debug,
}
struct Hide(HasDyn);
const fn no_inner_dyn_trait(_x: Hide) {}
const fn no_inner_dyn_trait2(x: Hide) {
x.0.field;
//~^ ERROR trait bounds other than `Sized`
}
const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) }
//~^ ERROR trait bounds other than `Sized`
fn main() {}

View File

@ -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

View File

@ -0,0 +1,29 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(min_const_fn)]
struct HasPtr {
field: fn(),
}
struct Hide(HasPtr);
fn field() {}
const fn no_inner_dyn_trait(_x: Hide) {}
const fn no_inner_dyn_trait2(x: Hide) {
x.0.field;
//~^ ERROR function pointers in const fn
}
const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasPtr { field }) }
//~^ ERROR function pointers in const fn
fn main() {}

View File

@ -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

View File

@ -0,0 +1,38 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![unstable(feature = "humans",
reason = "who ever let humans program computers,
we're apparently really bad at it",
issue = "0")]
#![feature(rustc_const_unstable, const_fn, foo)]
#![feature(staged_api)]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature="foo")]
const fn foo() -> u32 { 42 }
#[stable(feature = "rust1", since = "1.0.0")]
// can't call non-min_const_fn
const fn bar() -> u32 { foo() } //~ ERROR can only call other `min_const_fn`
#[unstable(feature = "rust1", issue="0")]
const fn foo2() -> u32 { 42 }
#[stable(feature = "rust1", since = "1.0.0")]
// can't call non-min_const_fn
const fn bar2() -> u32 { foo2() } //~ ERROR can only call other `min_const_fn`
#[stable(feature = "rust1", since = "1.0.0")]
// conformity is required, even with `const_fn` feature gate
const fn bar3() -> u32 { (5f32 + 6f32) as u32 } //~ ERROR only int, `bool` and `char` operations
fn main() {}

View File

@ -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

View File

@ -0,0 +1,38 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(min_const_fn)]
// ok
const unsafe fn foo4() -> i32 { 42 }
const unsafe fn foo5<T>() -> *const T { 0 as *const T }
const unsafe fn foo6<T>() -> *mut T { 0 as *mut T }
const fn no_unsafe() { unsafe {} }
// not ok
const fn foo8() -> i32 {
unsafe { foo4() } //~ ERROR unsafe operations are not allowed in const fn
}
const fn foo9() -> *const String {
unsafe { foo5::<String>() } //~ ERROR unsafe operations are not allowed in const fn
}
const fn foo10() -> *const Vec<std::cell::Cell<u32>> {
unsafe { foo6::<Vec<std::cell::Cell<u32>>>() } //~ ERROR not allowed in const fn
}
const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn
//~^ dereferencing raw pointers in constant functions
fn main() {}
const unsafe fn no_union() {
union Foo { x: (), y: () }
Foo { x: () }.y //~ ERROR not allowed in const fn
//~^ unions in const fn
}

View File

@ -0,0 +1,59 @@
error[E0658]: dereferencing raw pointers in constant functions is unstable (see issue #51911)
--> $DIR/min_const_fn_unsafe.rs:29:51
|
LL | const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn
| ^^
|
= help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable
error[E0658]: unions in const fn are unstable (see issue #51909)
--> $DIR/min_const_fn_unsafe.rs:36:5
|
LL | Foo { x: () }.y //~ ERROR not allowed in const fn
| ^^^^^^^^^^^^^^^
|
= help: add #![feature(const_fn_union)] to the crate attributes to enable
error: call to unsafe function is unsafe and unsafe operations are not allowed in const fn
--> $DIR/min_const_fn_unsafe.rs:21:14
|
LL | unsafe { foo4() } //~ ERROR unsafe operations are not allowed in const fn
| ^^^^^^ call to unsafe function
|
= note: consult the function's documentation for information on how to avoid undefined behavior
error: call to unsafe function is unsafe and unsafe operations are not allowed in const fn
--> $DIR/min_const_fn_unsafe.rs:24:14
|
LL | unsafe { foo5::<String>() } //~ ERROR unsafe operations are not allowed in const fn
| ^^^^^^^^^^^^^^^^ call to unsafe function
|
= note: consult the function's documentation for information on how to avoid undefined behavior
error: call to unsafe function is unsafe and unsafe operations are not allowed in const fn
--> $DIR/min_const_fn_unsafe.rs:27:14
|
LL | unsafe { foo6::<Vec<std::cell::Cell<u32>>>() } //~ ERROR not allowed in const fn
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
|
= note: consult the function's documentation for information on how to avoid undefined behavior
error: dereference of raw pointer is unsafe and unsafe operations are not allowed in const fn
--> $DIR/min_const_fn_unsafe.rs:29:51
|
LL | const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn
| ^^ dereference of raw pointer
|
= note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
error: access to union field is unsafe and unsafe operations are not allowed in const fn
--> $DIR/min_const_fn_unsafe.rs:36:5
|
LL | Foo { x: () }.y //~ ERROR not allowed in const fn
| ^^^^^^^^^^^^^^^ access to union field
|
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
error: aborting due to 7 previous errors
For more information about this error, try `rustc --explain E0658`.

View File

@ -4,8 +4,8 @@ error[E0308]: intrinsic has wrong type
LL | fn size_of<T>(); //~ ERROR E0308
| ^^^^^^^^^^^^^^^^ expected (), found usize
|
= note: expected type `unsafe extern "rust-intrinsic" fn()`
found type `unsafe extern "rust-intrinsic" fn() -> usize`
= note: expected type `extern "rust-intrinsic" fn()`
found type `extern "rust-intrinsic" fn() -> usize`
error: aborting due to previous error

View File

@ -8,9 +8,11 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test use of const fn without feature gate.
// Test use of const fn without the `const_fn` feature gate.
// `min_const_fn` is checked in its own file
#![feature(min_const_fn)]
const fn foo() -> usize { 0 } //~ ERROR const fn is unstable
const fn foo() -> usize { 0 } // ok
trait Foo {
const fn foo() -> u32; //~ ERROR const fn is unstable
@ -20,12 +22,11 @@ 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();

View File

@ -1,31 +1,23 @@
error[E0379]: trait fns cannot be declared const
--> $DIR/feature-gate-const_fn.rs:16:5
--> $DIR/feature-gate-const_fn.rs:18:5
|
LL | const fn foo() -> u32; //~ ERROR const fn is unstable
| ^^^^^ trait fns cannot be const
error[E0379]: trait fns cannot be declared const
--> $DIR/feature-gate-const_fn.rs:18:5
--> $DIR/feature-gate-const_fn.rs:20:5
|
LL | const fn bar() -> u32 { 0 } //~ ERROR const fn is unstable
| ^^^^^ trait fns cannot be const
error[E0379]: trait fns cannot be declared const
--> $DIR/feature-gate-const_fn.rs:27:5
--> $DIR/feature-gate-const_fn.rs:29:5
|
LL | const fn foo() -> u32 { 0 } //~ ERROR const fn is unstable
LL | const fn foo() -> u32 { 0 } //~ ERROR trait fns cannot be declared const
| ^^^^^ trait fns cannot be const
error[E0658]: const fn is unstable (see issue #24111)
--> $DIR/feature-gate-const_fn.rs:13:1
|
LL | const fn foo() -> usize { 0 } //~ ERROR const fn is unstable
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: add #![feature(const_fn)] to the crate attributes to enable
error[E0658]: const fn is unstable (see issue #24111)
--> $DIR/feature-gate-const_fn.rs:16:5
--> $DIR/feature-gate-const_fn.rs:18:5
|
LL | const fn foo() -> u32; //~ ERROR const fn is unstable
| ^^^^^^^^^^^^^^^^^^^^^^
@ -33,30 +25,14 @@ LL | const fn foo() -> u32; //~ ERROR const fn is unstable
= help: add #![feature(const_fn)] to the crate attributes to enable
error[E0658]: const fn is unstable (see issue #24111)
--> $DIR/feature-gate-const_fn.rs:18:5
--> $DIR/feature-gate-const_fn.rs:20:5
|
LL | const fn bar() -> u32 { 0 } //~ ERROR const fn is unstable
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: add #![feature(const_fn)] to the crate attributes to enable
error[E0658]: const fn is unstable (see issue #24111)
--> $DIR/feature-gate-const_fn.rs:23:5
|
LL | const fn baz() -> u32 { 0 } //~ ERROR const fn is unstable
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: add #![feature(const_fn)] to the crate attributes to enable
error[E0658]: const fn is unstable (see issue #24111)
--> $DIR/feature-gate-const_fn.rs:27:5
|
LL | const fn foo() -> u32 { 0 } //~ ERROR const fn is unstable
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: add #![feature(const_fn)] to the crate attributes to enable
error: aborting due to 8 previous errors
error: aborting due to 5 previous errors
Some errors occurred: E0379, E0658.
For more information about an error, try `rustc --explain E0379`.

View File

@ -0,0 +1,46 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test use of min_const_fn without feature gate.
const fn foo() -> usize { 0 } //~ ERROR const fn is unstable
trait Foo {
const fn foo() -> u32; //~ ERROR const fn is unstable
//~| ERROR trait fns cannot be declared const
const fn bar() -> u32 { 0 } //~ ERROR const fn is unstable
//~| ERROR trait fns cannot be declared const
}
impl Foo {
const fn baz() -> u32 { 0 } //~ ERROR const fn is unstable
}
impl Foo for u32 {
const fn foo() -> u32 { 0 } //~ ERROR const fn is unstable
//~| ERROR trait fns cannot be declared const
}
static FOO: usize = foo();
const BAR: usize = foo();
macro_rules! constant {
($n:ident: $t:ty = $v:expr) => {
const $n: $t = $v;
}
}
constant! {
BAZ: usize = foo()
}
fn main() {
let x: [usize; foo()] = [];
}

View File

@ -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`.