Auto merge of #66275 - oli-obk:organize-intrinsics-promotion-checks, r=RalfJung
Organize intrinsics promotion checks cc @vertexclique supersedes #61835 r? @RalfJung
This commit is contained in:
commit
7fa046534e
16 changed files with 248 additions and 167 deletions
|
@ -939,6 +939,7 @@ extern "rust-intrinsic" {
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
#[rustc_const_unstable(feature = "const_transmute")]
|
||||||
pub fn transmute<T, U>(e: T) -> U;
|
pub fn transmute<T, U>(e: T) -> U;
|
||||||
|
|
||||||
/// Returns `true` if the actual type given as `T` requires drop
|
/// Returns `true` if the actual type given as `T` requires drop
|
||||||
|
|
|
@ -2,7 +2,8 @@ use crate::ty::query::Providers;
|
||||||
use crate::hir::def_id::DefId;
|
use crate::hir::def_id::DefId;
|
||||||
use crate::hir;
|
use crate::hir;
|
||||||
use crate::ty::TyCtxt;
|
use crate::ty::TyCtxt;
|
||||||
use syntax_pos::symbol::Symbol;
|
use syntax_pos::symbol::{sym, Symbol};
|
||||||
|
use rustc_target::spec::abi::Abi;
|
||||||
use crate::hir::map::blocks::FnLikeNode;
|
use crate::hir::map::blocks::FnLikeNode;
|
||||||
use syntax::attr;
|
use syntax::attr;
|
||||||
|
|
||||||
|
@ -35,12 +36,51 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if the `def_id` refers to an intrisic which we've whitelisted
|
||||||
|
/// for being called from stable `const fn`s (`min_const_fn`).
|
||||||
|
///
|
||||||
|
/// Adding more intrinsics requires sign-off from @rust-lang/lang.
|
||||||
|
///
|
||||||
|
/// This list differs from the list in `is_const_intrinsic` in the sense that any item on this
|
||||||
|
/// list must be on the `is_const_intrinsic` list, too, because if an intrinsic is callable from
|
||||||
|
/// stable, it must be callable at all.
|
||||||
|
fn is_intrinsic_min_const_fn(self, def_id: DefId) -> bool {
|
||||||
|
match self.item_name(def_id) {
|
||||||
|
| sym::size_of
|
||||||
|
| sym::min_align_of
|
||||||
|
| sym::needs_drop
|
||||||
|
// Arithmetic:
|
||||||
|
| sym::add_with_overflow // ~> .overflowing_add
|
||||||
|
| sym::sub_with_overflow // ~> .overflowing_sub
|
||||||
|
| sym::mul_with_overflow // ~> .overflowing_mul
|
||||||
|
| sym::wrapping_add // ~> .wrapping_add
|
||||||
|
| sym::wrapping_sub // ~> .wrapping_sub
|
||||||
|
| sym::wrapping_mul // ~> .wrapping_mul
|
||||||
|
| sym::saturating_add // ~> .saturating_add
|
||||||
|
| sym::saturating_sub // ~> .saturating_sub
|
||||||
|
| sym::unchecked_shl // ~> .wrapping_shl
|
||||||
|
| sym::unchecked_shr // ~> .wrapping_shr
|
||||||
|
| sym::rotate_left // ~> .rotate_left
|
||||||
|
| sym::rotate_right // ~> .rotate_right
|
||||||
|
| sym::ctpop // ~> .count_ones
|
||||||
|
| sym::ctlz // ~> .leading_zeros
|
||||||
|
| sym::cttz // ~> .trailing_zeros
|
||||||
|
| sym::bswap // ~> .swap_bytes
|
||||||
|
| sym::bitreverse // ~> .reverse_bits
|
||||||
|
=> true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns `true` if this function must conform to `min_const_fn`
|
/// Returns `true` if this function must conform to `min_const_fn`
|
||||||
pub fn is_min_const_fn(self, def_id: DefId) -> bool {
|
pub fn is_min_const_fn(self, def_id: DefId) -> bool {
|
||||||
// Bail out if the signature doesn't contain `const`
|
// Bail out if the signature doesn't contain `const`
|
||||||
if !self.is_const_fn_raw(def_id) {
|
if !self.is_const_fn_raw(def_id) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if let Abi::RustIntrinsic = self.fn_sig(def_id).abi() {
|
||||||
|
return self.is_intrinsic_min_const_fn(def_id);
|
||||||
|
}
|
||||||
|
|
||||||
if self.features().staged_api {
|
if self.features().staged_api {
|
||||||
// in order for a libstd function to be considered min_const_fn
|
// in order for a libstd function to be considered min_const_fn
|
||||||
|
@ -63,13 +103,82 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
|
|
||||||
|
|
||||||
pub fn provide(providers: &mut Providers<'_>) {
|
pub fn provide(providers: &mut Providers<'_>) {
|
||||||
/// only checks whether the function has a `const` modifier
|
/// Const evaluability whitelist is here to check evaluability at the
|
||||||
|
/// top level beforehand.
|
||||||
|
fn is_const_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> Option<bool> {
|
||||||
|
match tcx.fn_sig(def_id).abi() {
|
||||||
|
Abi::RustIntrinsic |
|
||||||
|
Abi::PlatformIntrinsic => {
|
||||||
|
// FIXME: deduplicate these two lists as much as possible
|
||||||
|
match tcx.item_name(def_id) {
|
||||||
|
// Keep this list in the same order as the match patterns in
|
||||||
|
// `librustc_mir/interpret/intrinsics.rs`
|
||||||
|
|
||||||
|
// This whitelist is a list of intrinsics that have a miri-engine implementation
|
||||||
|
// and can thus be called when enabling enough feature gates. The similar
|
||||||
|
// whitelist in `is_intrinsic_min_const_fn` (in this file), exists for allowing
|
||||||
|
// the intrinsics to be called by stable const fns.
|
||||||
|
| sym::caller_location
|
||||||
|
|
||||||
|
| sym::min_align_of
|
||||||
|
| sym::pref_align_of
|
||||||
|
| sym::needs_drop
|
||||||
|
| sym::size_of
|
||||||
|
| sym::type_id
|
||||||
|
| sym::type_name
|
||||||
|
|
||||||
|
| sym::ctpop
|
||||||
|
| sym::cttz
|
||||||
|
| sym::cttz_nonzero
|
||||||
|
| sym::ctlz
|
||||||
|
| sym::ctlz_nonzero
|
||||||
|
| sym::bswap
|
||||||
|
| sym::bitreverse
|
||||||
|
|
||||||
|
| sym::wrapping_add
|
||||||
|
| sym::wrapping_sub
|
||||||
|
| sym::wrapping_mul
|
||||||
|
| sym::add_with_overflow
|
||||||
|
| sym::sub_with_overflow
|
||||||
|
| sym::mul_with_overflow
|
||||||
|
|
||||||
|
| sym::saturating_add
|
||||||
|
| sym::saturating_sub
|
||||||
|
|
||||||
|
| sym::unchecked_shl
|
||||||
|
| sym::unchecked_shr
|
||||||
|
|
||||||
|
| sym::rotate_left
|
||||||
|
| sym::rotate_right
|
||||||
|
|
||||||
|
| sym::ptr_offset_from
|
||||||
|
|
||||||
|
| sym::transmute
|
||||||
|
|
||||||
|
| sym::simd_insert
|
||||||
|
|
||||||
|
| sym::simd_extract
|
||||||
|
|
||||||
|
=> Some(true),
|
||||||
|
|
||||||
|
_ => Some(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks whether the function has a `const` modifier or, in case it is an intrinsic, whether
|
||||||
|
/// said intrinsic is on the whitelist for being const callable.
|
||||||
fn is_const_fn_raw(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
fn is_const_fn_raw(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
||||||
let hir_id = tcx.hir().as_local_hir_id(def_id)
|
let hir_id = tcx.hir().as_local_hir_id(def_id)
|
||||||
.expect("Non-local call to local provider is_const_fn");
|
.expect("Non-local call to local provider is_const_fn");
|
||||||
|
|
||||||
let node = tcx.hir().get(hir_id);
|
let node = tcx.hir().get(hir_id);
|
||||||
if let Some(fn_like) = FnLikeNode::from_node(node) {
|
|
||||||
|
if let Some(whitelisted) = is_const_intrinsic(tcx, def_id) {
|
||||||
|
whitelisted
|
||||||
|
} else if let Some(fn_like) = FnLikeNode::from_node(node) {
|
||||||
fn_like.constness() == hir::Constness::Const
|
fn_like.constness() == hir::Constness::Const
|
||||||
} else if let hir::Node::Ctor(_) = node {
|
} else if let hir::Node::Ctor(_) = node {
|
||||||
true
|
true
|
||||||
|
|
|
@ -408,10 +408,6 @@ declare_features! (
|
||||||
/// Allows using `#[doc(keyword = "...")]`.
|
/// Allows using `#[doc(keyword = "...")]`.
|
||||||
(active, doc_keyword, "1.28.0", Some(51315), None),
|
(active, doc_keyword, "1.28.0", Some(51315), None),
|
||||||
|
|
||||||
/// 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 using `try {...}` expressions.
|
/// Allows using `try {...}` expressions.
|
||||||
(active, try_blocks, "1.29.0", Some(31436), None),
|
(active, try_blocks, "1.29.0", Some(31436), None),
|
||||||
|
|
||||||
|
|
|
@ -1360,10 +1360,16 @@ impl<'a, 'tcx> CrateMetadata {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This replicates some of the logic of the crate-local `is_const_fn_raw` query, because we
|
||||||
|
// don't serialize constness for tuple variant and tuple struct constructors.
|
||||||
fn is_const_fn_raw(&self, id: DefIndex) -> bool {
|
fn is_const_fn_raw(&self, id: DefIndex) -> bool {
|
||||||
let constness = match self.kind(id) {
|
let constness = match self.kind(id) {
|
||||||
EntryKind::Method(data) => data.decode(self).fn_data.constness,
|
EntryKind::Method(data) => data.decode(self).fn_data.constness,
|
||||||
EntryKind::Fn(data) => data.decode(self).constness,
|
EntryKind::Fn(data) => data.decode(self).constness,
|
||||||
|
// Some intrinsics can be const fn. While we could recompute this (at least until we
|
||||||
|
// stop having hardcoded whitelists and move to stability attributes), it seems cleaner
|
||||||
|
// to treat all const fns equally.
|
||||||
|
EntryKind::ForeignFn(data) => data.decode(self).constness,
|
||||||
EntryKind::Variant(..) | EntryKind::Struct(..) => hir::Constness::Const,
|
EntryKind::Variant(..) | EntryKind::Struct(..) => hir::Constness::Const,
|
||||||
_ => hir::Constness::NotConst,
|
_ => hir::Constness::NotConst,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1525,7 +1525,11 @@ impl EncodeContext<'tcx> {
|
||||||
hir::ForeignItemKind::Fn(_, ref names, _) => {
|
hir::ForeignItemKind::Fn(_, ref names, _) => {
|
||||||
let data = FnData {
|
let data = FnData {
|
||||||
asyncness: hir::IsAsync::NotAsync,
|
asyncness: hir::IsAsync::NotAsync,
|
||||||
constness: hir::Constness::NotConst,
|
constness: if self.tcx.is_const_fn_raw(def_id) {
|
||||||
|
hir::Constness::Const
|
||||||
|
} else {
|
||||||
|
hir::Constness::NotConst
|
||||||
|
},
|
||||||
param_names: self.encode_fn_param_names(names),
|
param_names: self.encode_fn_param_names(names),
|
||||||
};
|
};
|
||||||
EntryKind::ForeignFn(self.lazy(data))
|
EntryKind::ForeignFn(self.lazy(data))
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
//! looking at their MIR. Intrinsics/functions supported here are shared by CTFE
|
//! looking at their MIR. Intrinsics/functions supported here are shared by CTFE
|
||||||
//! and miri.
|
//! and miri.
|
||||||
|
|
||||||
use syntax::symbol::Symbol;
|
use syntax_pos::symbol::{sym, Symbol};
|
||||||
use syntax_pos::Span;
|
use syntax_pos::Span;
|
||||||
use rustc::ty;
|
use rustc::ty;
|
||||||
use rustc::ty::layout::{LayoutOf, Primitive, Size};
|
use rustc::ty::layout::{LayoutOf, Primitive, Size};
|
||||||
|
@ -22,7 +22,7 @@ mod caller_location;
|
||||||
mod type_name;
|
mod type_name;
|
||||||
|
|
||||||
fn numeric_intrinsic<'tcx, Tag>(
|
fn numeric_intrinsic<'tcx, Tag>(
|
||||||
name: &str,
|
name: Symbol,
|
||||||
bits: u128,
|
bits: u128,
|
||||||
kind: Primitive,
|
kind: Primitive,
|
||||||
) -> InterpResult<'tcx, Scalar<Tag>> {
|
) -> InterpResult<'tcx, Scalar<Tag>> {
|
||||||
|
@ -32,11 +32,11 @@ fn numeric_intrinsic<'tcx, Tag>(
|
||||||
};
|
};
|
||||||
let extra = 128 - size.bits() as u128;
|
let extra = 128 - size.bits() as u128;
|
||||||
let bits_out = match name {
|
let bits_out = match name {
|
||||||
"ctpop" => bits.count_ones() as u128,
|
sym::ctpop => bits.count_ones() as u128,
|
||||||
"ctlz" => bits.leading_zeros() as u128 - extra,
|
sym::ctlz => bits.leading_zeros() as u128 - extra,
|
||||||
"cttz" => (bits << extra).trailing_zeros() as u128 - extra,
|
sym::cttz => (bits << extra).trailing_zeros() as u128 - extra,
|
||||||
"bswap" => (bits << extra).swap_bytes(),
|
sym::bswap => (bits << extra).swap_bytes(),
|
||||||
"bitreverse" => (bits << extra).reverse_bits(),
|
sym::bitreverse => (bits << extra).reverse_bits(),
|
||||||
_ => bug!("not a numeric intrinsic: {}", name),
|
_ => bug!("not a numeric intrinsic: {}", name),
|
||||||
};
|
};
|
||||||
Ok(Scalar::from_uint(bits_out, size))
|
Ok(Scalar::from_uint(bits_out, size))
|
||||||
|
@ -51,9 +51,9 @@ crate fn eval_nullary_intrinsic<'tcx>(
|
||||||
substs: SubstsRef<'tcx>,
|
substs: SubstsRef<'tcx>,
|
||||||
) -> InterpResult<'tcx, &'tcx ty::Const<'tcx>> {
|
) -> InterpResult<'tcx, &'tcx ty::Const<'tcx>> {
|
||||||
let tp_ty = substs.type_at(0);
|
let tp_ty = substs.type_at(0);
|
||||||
let name = &*tcx.item_name(def_id).as_str();
|
let name = tcx.item_name(def_id);
|
||||||
Ok(match name {
|
Ok(match name {
|
||||||
"type_name" => {
|
sym::type_name => {
|
||||||
let alloc = type_name::alloc_type_name(tcx, tp_ty);
|
let alloc = type_name::alloc_type_name(tcx, tp_ty);
|
||||||
tcx.mk_const(ty::Const {
|
tcx.mk_const(ty::Const {
|
||||||
val: ty::ConstKind::Value(ConstValue::Slice {
|
val: ty::ConstKind::Value(ConstValue::Slice {
|
||||||
|
@ -64,20 +64,20 @@ crate fn eval_nullary_intrinsic<'tcx>(
|
||||||
ty: tcx.mk_static_str(),
|
ty: tcx.mk_static_str(),
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
"needs_drop" => ty::Const::from_bool(tcx, tp_ty.needs_drop(tcx, param_env)),
|
sym::needs_drop => ty::Const::from_bool(tcx, tp_ty.needs_drop(tcx, param_env)),
|
||||||
"size_of" |
|
sym::size_of |
|
||||||
"min_align_of" |
|
sym::min_align_of |
|
||||||
"pref_align_of" => {
|
sym::pref_align_of => {
|
||||||
let layout = tcx.layout_of(param_env.and(tp_ty)).map_err(|e| err_inval!(Layout(e)))?;
|
let layout = tcx.layout_of(param_env.and(tp_ty)).map_err(|e| err_inval!(Layout(e)))?;
|
||||||
let n = match name {
|
let n = match name {
|
||||||
"pref_align_of" => layout.align.pref.bytes(),
|
sym::pref_align_of => layout.align.pref.bytes(),
|
||||||
"min_align_of" => layout.align.abi.bytes(),
|
sym::min_align_of => layout.align.abi.bytes(),
|
||||||
"size_of" => layout.size.bytes(),
|
sym::size_of => layout.size.bytes(),
|
||||||
_ => bug!(),
|
_ => bug!(),
|
||||||
};
|
};
|
||||||
ty::Const::from_usize(tcx, n)
|
ty::Const::from_usize(tcx, n)
|
||||||
},
|
},
|
||||||
"type_id" => ty::Const::from_bits(
|
sym::type_id => ty::Const::from_bits(
|
||||||
tcx,
|
tcx,
|
||||||
tcx.type_id_hash(tp_ty).into(),
|
tcx.type_id_hash(tp_ty).into(),
|
||||||
param_env.and(tcx.types.u64),
|
param_env.and(tcx.types.u64),
|
||||||
|
@ -96,30 +96,32 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
ret: Option<(PlaceTy<'tcx, M::PointerTag>, mir::BasicBlock)>,
|
ret: Option<(PlaceTy<'tcx, M::PointerTag>, mir::BasicBlock)>,
|
||||||
) -> InterpResult<'tcx, bool> {
|
) -> InterpResult<'tcx, bool> {
|
||||||
let substs = instance.substs;
|
let substs = instance.substs;
|
||||||
let intrinsic_name = &*self.tcx.item_name(instance.def_id()).as_str();
|
let intrinsic_name = self.tcx.item_name(instance.def_id());
|
||||||
|
|
||||||
// We currently do not handle any intrinsics that are *allowed* to diverge,
|
// We currently do not handle any intrinsics that are *allowed* to diverge,
|
||||||
// but `transmute` could lack a return place in case of UB.
|
// but `transmute` could lack a return place in case of UB.
|
||||||
let (dest, ret) = match ret {
|
let (dest, ret) = match ret {
|
||||||
Some(p) => p,
|
Some(p) => p,
|
||||||
None => match intrinsic_name {
|
None => match intrinsic_name {
|
||||||
"transmute" => throw_ub!(Unreachable),
|
sym::transmute => throw_ub!(Unreachable),
|
||||||
_ => return Ok(false),
|
_ => return Ok(false),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Keep the patterns in this match ordered the same as the list in
|
||||||
|
// `src/librustc/ty/constness.rs`
|
||||||
match intrinsic_name {
|
match intrinsic_name {
|
||||||
"caller_location" => {
|
sym::caller_location => {
|
||||||
let location = self.alloc_caller_location_for_span(span);
|
let location = self.alloc_caller_location_for_span(span);
|
||||||
self.write_scalar(location.ptr, dest)?;
|
self.write_scalar(location.ptr, dest)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
"min_align_of" |
|
sym::min_align_of |
|
||||||
"pref_align_of" |
|
sym::pref_align_of |
|
||||||
"needs_drop" |
|
sym::needs_drop |
|
||||||
"size_of" |
|
sym::size_of |
|
||||||
"type_id" |
|
sym::type_id |
|
||||||
"type_name" => {
|
sym::type_name => {
|
||||||
let gid = GlobalId {
|
let gid = GlobalId {
|
||||||
instance,
|
instance,
|
||||||
promoted: None,
|
promoted: None,
|
||||||
|
@ -129,13 +131,13 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
self.copy_op(val, dest)?;
|
self.copy_op(val, dest)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
| "ctpop"
|
| sym::ctpop
|
||||||
| "cttz"
|
| sym::cttz
|
||||||
| "cttz_nonzero"
|
| sym::cttz_nonzero
|
||||||
| "ctlz"
|
| sym::ctlz
|
||||||
| "ctlz_nonzero"
|
| sym::ctlz_nonzero
|
||||||
| "bswap"
|
| sym::bswap
|
||||||
| "bitreverse" => {
|
| sym::bitreverse => {
|
||||||
let ty = substs.type_at(0);
|
let ty = substs.type_at(0);
|
||||||
let layout_of = self.layout_of(ty)?;
|
let layout_of = self.layout_of(ty)?;
|
||||||
let val = self.read_scalar(args[0])?.not_undef()?;
|
let val = self.read_scalar(args[0])?.not_undef()?;
|
||||||
|
@ -144,31 +146,32 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
ty::layout::Abi::Scalar(ref scalar) => scalar.value,
|
ty::layout::Abi::Scalar(ref scalar) => scalar.value,
|
||||||
_ => throw_unsup!(TypeNotPrimitive(ty)),
|
_ => throw_unsup!(TypeNotPrimitive(ty)),
|
||||||
};
|
};
|
||||||
let out_val = if intrinsic_name.ends_with("_nonzero") {
|
let (nonzero, intrinsic_name) = match intrinsic_name {
|
||||||
if bits == 0 {
|
sym::cttz_nonzero => (true, sym::cttz),
|
||||||
throw_ub_format!("`{}` called on 0", intrinsic_name);
|
sym::ctlz_nonzero => (true, sym::ctlz),
|
||||||
}
|
other => (false, other),
|
||||||
numeric_intrinsic(intrinsic_name.trim_end_matches("_nonzero"), bits, kind)?
|
|
||||||
} else {
|
|
||||||
numeric_intrinsic(intrinsic_name, bits, kind)?
|
|
||||||
};
|
};
|
||||||
|
if nonzero && bits == 0 {
|
||||||
|
throw_ub_format!("`{}_nonzero` called on 0", intrinsic_name);
|
||||||
|
}
|
||||||
|
let out_val = numeric_intrinsic(intrinsic_name, bits, kind)?;
|
||||||
self.write_scalar(out_val, dest)?;
|
self.write_scalar(out_val, dest)?;
|
||||||
}
|
}
|
||||||
| "wrapping_add"
|
| sym::wrapping_add
|
||||||
| "wrapping_sub"
|
| sym::wrapping_sub
|
||||||
| "wrapping_mul"
|
| sym::wrapping_mul
|
||||||
| "add_with_overflow"
|
| sym::add_with_overflow
|
||||||
| "sub_with_overflow"
|
| sym::sub_with_overflow
|
||||||
| "mul_with_overflow" => {
|
| sym::mul_with_overflow => {
|
||||||
let lhs = self.read_immediate(args[0])?;
|
let lhs = self.read_immediate(args[0])?;
|
||||||
let rhs = self.read_immediate(args[1])?;
|
let rhs = self.read_immediate(args[1])?;
|
||||||
let (bin_op, ignore_overflow) = match intrinsic_name {
|
let (bin_op, ignore_overflow) = match intrinsic_name {
|
||||||
"wrapping_add" => (BinOp::Add, true),
|
sym::wrapping_add => (BinOp::Add, true),
|
||||||
"wrapping_sub" => (BinOp::Sub, true),
|
sym::wrapping_sub => (BinOp::Sub, true),
|
||||||
"wrapping_mul" => (BinOp::Mul, true),
|
sym::wrapping_mul => (BinOp::Mul, true),
|
||||||
"add_with_overflow" => (BinOp::Add, false),
|
sym::add_with_overflow => (BinOp::Add, false),
|
||||||
"sub_with_overflow" => (BinOp::Sub, false),
|
sym::sub_with_overflow => (BinOp::Sub, false),
|
||||||
"mul_with_overflow" => (BinOp::Mul, false),
|
sym::mul_with_overflow => (BinOp::Mul, false),
|
||||||
_ => bug!("Already checked for int ops")
|
_ => bug!("Already checked for int ops")
|
||||||
};
|
};
|
||||||
if ignore_overflow {
|
if ignore_overflow {
|
||||||
|
@ -177,10 +180,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
self.binop_with_overflow(bin_op, lhs, rhs, dest)?;
|
self.binop_with_overflow(bin_op, lhs, rhs, dest)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"saturating_add" | "saturating_sub" => {
|
sym::saturating_add | sym::saturating_sub => {
|
||||||
let l = self.read_immediate(args[0])?;
|
let l = self.read_immediate(args[0])?;
|
||||||
let r = self.read_immediate(args[1])?;
|
let r = self.read_immediate(args[1])?;
|
||||||
let is_add = intrinsic_name == "saturating_add";
|
let is_add = intrinsic_name == sym::saturating_add;
|
||||||
let (val, overflowed, _ty) = self.overflowing_binary_op(if is_add {
|
let (val, overflowed, _ty) = self.overflowing_binary_op(if is_add {
|
||||||
BinOp::Add
|
BinOp::Add
|
||||||
} else {
|
} else {
|
||||||
|
@ -220,12 +223,12 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
};
|
};
|
||||||
self.write_scalar(val, dest)?;
|
self.write_scalar(val, dest)?;
|
||||||
}
|
}
|
||||||
"unchecked_shl" | "unchecked_shr" => {
|
sym::unchecked_shl | sym::unchecked_shr => {
|
||||||
let l = self.read_immediate(args[0])?;
|
let l = self.read_immediate(args[0])?;
|
||||||
let r = self.read_immediate(args[1])?;
|
let r = self.read_immediate(args[1])?;
|
||||||
let bin_op = match intrinsic_name {
|
let bin_op = match intrinsic_name {
|
||||||
"unchecked_shl" => BinOp::Shl,
|
sym::unchecked_shl => BinOp::Shl,
|
||||||
"unchecked_shr" => BinOp::Shr,
|
sym::unchecked_shr => BinOp::Shr,
|
||||||
_ => bug!("Already checked for int ops")
|
_ => bug!("Already checked for int ops")
|
||||||
};
|
};
|
||||||
let (val, overflowed, _ty) = self.overflowing_binary_op(bin_op, l, r)?;
|
let (val, overflowed, _ty) = self.overflowing_binary_op(bin_op, l, r)?;
|
||||||
|
@ -236,7 +239,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
}
|
}
|
||||||
self.write_scalar(val, dest)?;
|
self.write_scalar(val, dest)?;
|
||||||
}
|
}
|
||||||
"rotate_left" | "rotate_right" => {
|
sym::rotate_left | sym::rotate_right => {
|
||||||
// rotate_left: (X << (S % BW)) | (X >> ((BW - S) % BW))
|
// rotate_left: (X << (S % BW)) | (X >> ((BW - S) % BW))
|
||||||
// rotate_right: (X << ((BW - S) % BW)) | (X >> (S % BW))
|
// rotate_right: (X << ((BW - S) % BW)) | (X >> (S % BW))
|
||||||
let layout = self.layout_of(substs.type_at(0))?;
|
let layout = self.layout_of(substs.type_at(0))?;
|
||||||
|
@ -247,7 +250,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
let width_bits = layout.size.bits() as u128;
|
let width_bits = layout.size.bits() as u128;
|
||||||
let shift_bits = raw_shift_bits % width_bits;
|
let shift_bits = raw_shift_bits % width_bits;
|
||||||
let inv_shift_bits = (width_bits - shift_bits) % width_bits;
|
let inv_shift_bits = (width_bits - shift_bits) % width_bits;
|
||||||
let result_bits = if intrinsic_name == "rotate_left" {
|
let result_bits = if intrinsic_name == sym::rotate_left {
|
||||||
(val_bits << shift_bits) | (val_bits >> inv_shift_bits)
|
(val_bits << shift_bits) | (val_bits >> inv_shift_bits)
|
||||||
} else {
|
} else {
|
||||||
(val_bits >> shift_bits) | (val_bits << inv_shift_bits)
|
(val_bits >> shift_bits) | (val_bits << inv_shift_bits)
|
||||||
|
@ -257,7 +260,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
self.write_scalar(result, dest)?;
|
self.write_scalar(result, dest)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
"ptr_offset_from" => {
|
sym::ptr_offset_from => {
|
||||||
let isize_layout = self.layout_of(self.tcx.types.isize)?;
|
let isize_layout = self.layout_of(self.tcx.types.isize)?;
|
||||||
let a = self.read_immediate(args[0])?.to_scalar()?;
|
let a = self.read_immediate(args[0])?.to_scalar()?;
|
||||||
let b = self.read_immediate(args[1])?.to_scalar()?;
|
let b = self.read_immediate(args[1])?.to_scalar()?;
|
||||||
|
@ -303,10 +306,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
"transmute" => {
|
sym::transmute => {
|
||||||
self.copy_op_transmute(args[0], dest)?;
|
self.copy_op_transmute(args[0], dest)?;
|
||||||
}
|
}
|
||||||
"simd_insert" => {
|
sym::simd_insert => {
|
||||||
let index = u64::from(self.read_scalar(args[1])?.to_u32()?);
|
let index = u64::from(self.read_scalar(args[1])?.to_u32()?);
|
||||||
let elem = args[2];
|
let elem = args[2];
|
||||||
let input = args[0];
|
let input = args[0];
|
||||||
|
@ -337,7 +340,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
self.copy_op(value, place)?;
|
self.copy_op(value, place)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"simd_extract" => {
|
sym::simd_extract => {
|
||||||
let index = u64::from(self.read_scalar(args[1])?.to_u32()?);
|
let index = u64::from(self.read_scalar(args[1])?.to_u32()?);
|
||||||
let (len, e_ty) = args[0].layout.ty.simd_size_and_type(self.tcx.tcx);
|
let (len, e_ty) = args[0].layout.ty.simd_size_and_type(self.tcx.tcx);
|
||||||
assert!(
|
assert!(
|
||||||
|
|
|
@ -326,22 +326,6 @@ impl NonConstOp for ThreadLocalAccess {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Transmute;
|
|
||||||
impl NonConstOp for Transmute {
|
|
||||||
fn feature_gate(tcx: TyCtxt<'_>) -> Option<bool> {
|
|
||||||
Some(tcx.features().const_transmute)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
|
|
||||||
feature_err(
|
|
||||||
&item.tcx.sess.parse_sess, sym::const_transmute, span,
|
|
||||||
&format!("The use of std::mem::transmute() is gated in {}s", item.const_kind())
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct UnionAccess;
|
pub struct UnionAccess;
|
||||||
impl NonConstOp for UnionAccess {
|
impl NonConstOp for UnionAccess {
|
||||||
|
|
|
@ -8,7 +8,6 @@ use rustc::traits::{self, TraitEngine};
|
||||||
use rustc::ty::cast::CastTy;
|
use rustc::ty::cast::CastTy;
|
||||||
use rustc::ty::{self, TyCtxt};
|
use rustc::ty::{self, TyCtxt};
|
||||||
use rustc_index::bit_set::BitSet;
|
use rustc_index::bit_set::BitSet;
|
||||||
use rustc_target::spec::abi::Abi;
|
|
||||||
use rustc_error_codes::*;
|
use rustc_error_codes::*;
|
||||||
use syntax::symbol::sym;
|
use syntax::symbol::sym;
|
||||||
use syntax_pos::Span;
|
use syntax_pos::Span;
|
||||||
|
@ -202,7 +201,7 @@ impl Validator<'a, 'mir, 'tcx> {
|
||||||
let Item { tcx, body, def_id, const_kind, .. } = *self.item;
|
let Item { tcx, body, def_id, const_kind, .. } = *self.item;
|
||||||
|
|
||||||
let use_min_const_fn_checks =
|
let use_min_const_fn_checks =
|
||||||
tcx.is_min_const_fn(def_id)
|
(const_kind == Some(ConstKind::ConstFn) && tcx.is_min_const_fn(def_id))
|
||||||
&& !tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you;
|
&& !tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you;
|
||||||
|
|
||||||
if use_min_const_fn_checks {
|
if use_min_const_fn_checks {
|
||||||
|
@ -564,23 +563,6 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
|
||||||
};
|
};
|
||||||
|
|
||||||
// At this point, we are calling a function whose `DefId` is known...
|
// At this point, we are calling a function whose `DefId` is known...
|
||||||
|
|
||||||
if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = self.tcx.fn_sig(def_id).abi() {
|
|
||||||
assert!(!self.tcx.is_const_fn(def_id));
|
|
||||||
|
|
||||||
if self.tcx.item_name(def_id) == sym::transmute {
|
|
||||||
self.check_op(ops::Transmute);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// To preserve the current semantics, we return early, allowing all
|
|
||||||
// intrinsics (except `transmute`) to pass unchecked to miri.
|
|
||||||
//
|
|
||||||
// FIXME: We should keep a whitelist of allowed intrinsics (or at least a
|
|
||||||
// blacklist of unimplemented ones) and fail here instead.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.tcx.is_const_fn(def_id) {
|
if self.tcx.is_const_fn(def_id) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ use rustc::hir::def_id::DefId;
|
||||||
use rustc::hir;
|
use rustc::hir;
|
||||||
use rustc::mir::*;
|
use rustc::mir::*;
|
||||||
use rustc::ty::{self, Predicate, Ty, TyCtxt, adjustment::{PointerCast}};
|
use rustc::ty::{self, Predicate, Ty, TyCtxt, adjustment::{PointerCast}};
|
||||||
use rustc_target::spec::abi;
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use syntax_pos::Span;
|
use syntax_pos::Span;
|
||||||
use syntax::symbol::{sym, Symbol};
|
use syntax::symbol::{sym, Symbol};
|
||||||
|
@ -356,18 +355,8 @@ fn check_terminator(
|
||||||
} => {
|
} => {
|
||||||
let fn_ty = func.ty(body, tcx);
|
let fn_ty = func.ty(body, tcx);
|
||||||
if let ty::FnDef(def_id, _) = fn_ty.kind {
|
if let ty::FnDef(def_id, _) = fn_ty.kind {
|
||||||
|
if !tcx.is_min_const_fn(def_id) {
|
||||||
// some intrinsics are waved through if called inside the
|
|
||||||
// standard library. Users never need to call them directly
|
|
||||||
match tcx.fn_sig(def_id).abi() {
|
|
||||||
abi::Abi::RustIntrinsic => if !is_intrinsic_whitelisted(tcx, def_id) {
|
|
||||||
return Err((
|
return Err((
|
||||||
span,
|
|
||||||
"can only call a curated list of intrinsics in `min_const_fn`".into(),
|
|
||||||
))
|
|
||||||
},
|
|
||||||
abi::Abi::Rust if tcx.is_min_const_fn(def_id) => {},
|
|
||||||
abi::Abi::Rust => return Err((
|
|
||||||
span,
|
span,
|
||||||
format!(
|
format!(
|
||||||
"can only call other `const fn` within a `const fn`, \
|
"can only call other `const fn` within a `const fn`, \
|
||||||
|
@ -375,14 +364,7 @@ fn check_terminator(
|
||||||
func,
|
func,
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
)),
|
));
|
||||||
abi => return Err((
|
|
||||||
span,
|
|
||||||
format!(
|
|
||||||
"cannot call functions with `{}` abi in `min_const_fn`",
|
|
||||||
abi,
|
|
||||||
).into(),
|
|
||||||
)),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
check_operand(tcx, func, span, def_id, body)?;
|
check_operand(tcx, func, span, def_id, body)?;
|
||||||
|
@ -409,35 +391,3 @@ fn check_terminator(
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if the `def_id` refers to an intrisic which we've whitelisted
|
|
||||||
/// for being called from stable `const fn`s (`min_const_fn`).
|
|
||||||
///
|
|
||||||
/// Adding more intrinsics requires sign-off from @rust-lang/lang.
|
|
||||||
fn is_intrinsic_whitelisted(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
|
|
||||||
match &*tcx.item_name(def_id).as_str() {
|
|
||||||
| "size_of"
|
|
||||||
| "min_align_of"
|
|
||||||
| "needs_drop"
|
|
||||||
// Arithmetic:
|
|
||||||
| "add_with_overflow" // ~> .overflowing_add
|
|
||||||
| "sub_with_overflow" // ~> .overflowing_sub
|
|
||||||
| "mul_with_overflow" // ~> .overflowing_mul
|
|
||||||
| "wrapping_add" // ~> .wrapping_add
|
|
||||||
| "wrapping_sub" // ~> .wrapping_sub
|
|
||||||
| "wrapping_mul" // ~> .wrapping_mul
|
|
||||||
| "saturating_add" // ~> .saturating_add
|
|
||||||
| "saturating_sub" // ~> .saturating_sub
|
|
||||||
| "unchecked_shl" // ~> .wrapping_shl
|
|
||||||
| "unchecked_shr" // ~> .wrapping_shr
|
|
||||||
| "rotate_left" // ~> .rotate_left
|
|
||||||
| "rotate_right" // ~> .rotate_right
|
|
||||||
| "ctpop" // ~> .count_ones
|
|
||||||
| "ctlz" // ~> .leading_zeros
|
|
||||||
| "cttz" // ~> .trailing_zeros
|
|
||||||
| "bswap" // ~> .swap_bytes
|
|
||||||
| "bitreverse" // ~> .reverse_bits
|
|
||||||
=> true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -121,6 +121,7 @@ symbols! {
|
||||||
abi_vectorcall,
|
abi_vectorcall,
|
||||||
abi_x86_interrupt,
|
abi_x86_interrupt,
|
||||||
aborts,
|
aborts,
|
||||||
|
add_with_overflow,
|
||||||
advanced_slice_patterns,
|
advanced_slice_patterns,
|
||||||
adx_target_feature,
|
adx_target_feature,
|
||||||
alias,
|
alias,
|
||||||
|
@ -171,7 +172,10 @@ symbols! {
|
||||||
box_patterns,
|
box_patterns,
|
||||||
box_syntax,
|
box_syntax,
|
||||||
braced_empty_structs,
|
braced_empty_structs,
|
||||||
|
bswap,
|
||||||
|
bitreverse,
|
||||||
C,
|
C,
|
||||||
|
caller_location,
|
||||||
cdylib,
|
cdylib,
|
||||||
cfg,
|
cfg,
|
||||||
cfg_attr,
|
cfg_attr,
|
||||||
|
@ -226,6 +230,11 @@ symbols! {
|
||||||
crate_name,
|
crate_name,
|
||||||
crate_type,
|
crate_type,
|
||||||
crate_visibility_modifier,
|
crate_visibility_modifier,
|
||||||
|
ctpop,
|
||||||
|
cttz,
|
||||||
|
cttz_nonzero,
|
||||||
|
ctlz,
|
||||||
|
ctlz_nonzero,
|
||||||
custom_attribute,
|
custom_attribute,
|
||||||
custom_derive,
|
custom_derive,
|
||||||
custom_inner_attributes,
|
custom_inner_attributes,
|
||||||
|
@ -431,6 +440,7 @@ symbols! {
|
||||||
member_constraints,
|
member_constraints,
|
||||||
message,
|
message,
|
||||||
meta,
|
meta,
|
||||||
|
min_align_of,
|
||||||
min_const_fn,
|
min_const_fn,
|
||||||
min_const_unsafe_fn,
|
min_const_unsafe_fn,
|
||||||
mips_target_feature,
|
mips_target_feature,
|
||||||
|
@ -440,11 +450,13 @@ symbols! {
|
||||||
more_struct_aliases,
|
more_struct_aliases,
|
||||||
move_val_init,
|
move_val_init,
|
||||||
movbe_target_feature,
|
movbe_target_feature,
|
||||||
|
mul_with_overflow,
|
||||||
must_use,
|
must_use,
|
||||||
naked,
|
naked,
|
||||||
naked_functions,
|
naked_functions,
|
||||||
name,
|
name,
|
||||||
needs_allocator,
|
needs_allocator,
|
||||||
|
needs_drop,
|
||||||
needs_panic_runtime,
|
needs_panic_runtime,
|
||||||
negate_unsigned,
|
negate_unsigned,
|
||||||
never,
|
never,
|
||||||
|
@ -520,6 +532,7 @@ symbols! {
|
||||||
poll_with_tls_context,
|
poll_with_tls_context,
|
||||||
powerpc_target_feature,
|
powerpc_target_feature,
|
||||||
precise_pointer_size_matching,
|
precise_pointer_size_matching,
|
||||||
|
pref_align_of,
|
||||||
prelude,
|
prelude,
|
||||||
prelude_import,
|
prelude_import,
|
||||||
primitive,
|
primitive,
|
||||||
|
@ -536,6 +549,7 @@ symbols! {
|
||||||
proc_macro_non_items,
|
proc_macro_non_items,
|
||||||
proc_macro_path_invoc,
|
proc_macro_path_invoc,
|
||||||
profiler_runtime,
|
profiler_runtime,
|
||||||
|
ptr_offset_from,
|
||||||
pub_restricted,
|
pub_restricted,
|
||||||
pushpop_unsafe,
|
pushpop_unsafe,
|
||||||
quad_precision_float,
|
quad_precision_float,
|
||||||
|
@ -571,6 +585,8 @@ symbols! {
|
||||||
Return,
|
Return,
|
||||||
rhs,
|
rhs,
|
||||||
rlib,
|
rlib,
|
||||||
|
rotate_left,
|
||||||
|
rotate_right,
|
||||||
rt,
|
rt,
|
||||||
rtm_target_feature,
|
rtm_target_feature,
|
||||||
rust,
|
rust,
|
||||||
|
@ -638,14 +654,19 @@ symbols! {
|
||||||
rvalue_static_promotion,
|
rvalue_static_promotion,
|
||||||
sanitize,
|
sanitize,
|
||||||
sanitizer_runtime,
|
sanitizer_runtime,
|
||||||
|
saturating_add,
|
||||||
|
saturating_sub,
|
||||||
_Self,
|
_Self,
|
||||||
self_in_typedefs,
|
self_in_typedefs,
|
||||||
self_struct_ctor,
|
self_struct_ctor,
|
||||||
should_panic,
|
should_panic,
|
||||||
simd,
|
simd,
|
||||||
|
simd_extract,
|
||||||
simd_ffi,
|
simd_ffi,
|
||||||
|
simd_insert,
|
||||||
since,
|
since,
|
||||||
size,
|
size,
|
||||||
|
size_of,
|
||||||
slice_patterns,
|
slice_patterns,
|
||||||
slicing_syntax,
|
slicing_syntax,
|
||||||
soft,
|
soft,
|
||||||
|
@ -673,6 +694,7 @@ symbols! {
|
||||||
structural_match,
|
structural_match,
|
||||||
struct_variant,
|
struct_variant,
|
||||||
sty,
|
sty,
|
||||||
|
sub_with_overflow,
|
||||||
suggestion,
|
suggestion,
|
||||||
target_feature,
|
target_feature,
|
||||||
target_has_atomic,
|
target_has_atomic,
|
||||||
|
@ -708,6 +730,8 @@ symbols! {
|
||||||
Ty,
|
Ty,
|
||||||
ty,
|
ty,
|
||||||
type_alias_impl_trait,
|
type_alias_impl_trait,
|
||||||
|
type_id,
|
||||||
|
type_name,
|
||||||
TyCtxt,
|
TyCtxt,
|
||||||
TyKind,
|
TyKind,
|
||||||
type_alias_enum_variants,
|
type_alias_enum_variants,
|
||||||
|
@ -720,6 +744,8 @@ symbols! {
|
||||||
u64,
|
u64,
|
||||||
u8,
|
u8,
|
||||||
unboxed_closures,
|
unboxed_closures,
|
||||||
|
unchecked_shl,
|
||||||
|
unchecked_shr,
|
||||||
underscore_const_names,
|
underscore_const_names,
|
||||||
underscore_imports,
|
underscore_imports,
|
||||||
underscore_lifetimes,
|
underscore_lifetimes,
|
||||||
|
@ -753,6 +779,9 @@ symbols! {
|
||||||
while_let,
|
while_let,
|
||||||
windows,
|
windows,
|
||||||
windows_subsystem,
|
windows_subsystem,
|
||||||
|
wrapping_add,
|
||||||
|
wrapping_sub,
|
||||||
|
wrapping_mul,
|
||||||
Yield,
|
Yield,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
#![feature(core_intrinsics)]
|
||||||
|
fn main() {
|
||||||
|
// Test that calls to intrinsics are never promoted
|
||||||
|
let x: &'static usize =
|
||||||
|
&std::intrinsics::size_of::<i32>(); //~ ERROR temporary value dropped while borrowed
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
error[E0716]: temporary value dropped while borrowed
|
||||||
|
--> $DIR/const-eval-intrinsic-promotion.rs:5:10
|
||||||
|
|
|
||||||
|
LL | let x: &'static usize =
|
||||||
|
| -------------- type annotation requires that borrow lasts for `'static`
|
||||||
|
LL | &std::intrinsics::size_of::<i32>();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
|
||||||
|
LL | }
|
||||||
|
| - temporary value is freed at the end of this statement
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0716`.
|
|
@ -7,7 +7,7 @@ extern "C" {
|
||||||
const extern fn bar() {
|
const extern fn bar() {
|
||||||
unsafe {
|
unsafe {
|
||||||
regular_in_block();
|
regular_in_block();
|
||||||
//~^ ERROR: cannot call functions with `"C"` abi in `min_const_fn`
|
//~^ ERROR: can only call other `const fn` within a `const fn`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ extern fn regular() {}
|
||||||
const extern fn foo() {
|
const extern fn foo() {
|
||||||
unsafe {
|
unsafe {
|
||||||
regular();
|
regular();
|
||||||
//~^ ERROR: cannot call functions with `"C"` abi in `min_const_fn`
|
//~^ ERROR: can only call other `const fn` within a `const fn`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
error[E0723]: cannot call functions with `"C"` abi in `min_const_fn`
|
error[E0723]: can only call other `const fn` within a `const fn`, but `const regular_in_block` is not stable as `const fn`
|
||||||
--> $DIR/const-extern-fn-call-extern-fn.rs:9:9
|
--> $DIR/const-extern-fn-call-extern-fn.rs:9:9
|
||||||
|
|
|
|
||||||
LL | regular_in_block();
|
LL | regular_in_block();
|
||||||
|
@ -7,7 +7,7 @@ LL | regular_in_block();
|
||||||
= note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
|
= note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
|
||||||
= help: add `#![feature(const_fn)]` to the crate attributes to enable
|
= help: add `#![feature(const_fn)]` to the crate attributes to enable
|
||||||
|
|
||||||
error[E0723]: cannot call functions with `"C"` abi in `min_const_fn`
|
error[E0723]: can only call other `const fn` within a `const fn`, but `const regular` is not stable as `const fn`
|
||||||
--> $DIR/const-extern-fn-call-extern-fn.rs:18:9
|
--> $DIR/const-extern-fn-call-extern-fn.rs:18:9
|
||||||
|
|
|
|
||||||
LL | regular();
|
LL | regular();
|
||||||
|
|
|
@ -4,6 +4,6 @@ use std::mem;
|
||||||
struct Foo(u32);
|
struct Foo(u32);
|
||||||
|
|
||||||
const TRANSMUTED_U32: u32 = unsafe { mem::transmute(Foo(3)) };
|
const TRANSMUTED_U32: u32 = unsafe { mem::transmute(Foo(3)) };
|
||||||
//~^ ERROR The use of std::mem::transmute() is gated in constants
|
//~^ ERROR `std::intrinsics::transmute` is not yet stable as a const fn
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
error[E0658]: The use of std::mem::transmute() is gated in constants
|
error: `std::intrinsics::transmute` is not yet stable as a const fn
|
||||||
--> $DIR/feature-gate-const_transmute.rs:6:38
|
--> $DIR/feature-gate-const_transmute.rs:6:38
|
||||||
|
|
|
|
||||||
LL | const TRANSMUTED_U32: u32 = unsafe { mem::transmute(Foo(3)) };
|
LL | const TRANSMUTED_U32: u32 = unsafe { mem::transmute(Foo(3)) };
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: for more information, see https://github.com/rust-lang/rust/issues/53605
|
|
||||||
= help: add `#![feature(const_transmute)]` to the crate attributes to enable
|
= help: add `#![feature(const_transmute)]` to the crate attributes to enable
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0658`.
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue