1
Fork 0

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:
bors 2019-12-04 11:22:26 +00:00
commit 7fa046534e
16 changed files with 248 additions and 167 deletions

View file

@ -939,6 +939,7 @@ extern "rust-intrinsic" {
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_transmute")]
pub fn transmute<T, U>(e: T) -> U;
/// Returns `true` if the actual type given as `T` requires drop

View file

@ -2,7 +2,8 @@ use crate::ty::query::Providers;
use crate::hir::def_id::DefId;
use crate::hir;
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 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`
pub fn is_min_const_fn(self, def_id: DefId) -> bool {
// Bail out if the signature doesn't contain `const`
if !self.is_const_fn_raw(def_id) {
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 {
// 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<'_>) {
/// 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 {
let hir_id = tcx.hir().as_local_hir_id(def_id)
.expect("Non-local call to local provider is_const_fn");
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
} else if let hir::Node::Ctor(_) = node {
true

View file

@ -408,10 +408,6 @@ declare_features! (
/// Allows using `#[doc(keyword = "...")]`.
(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.
(active, try_blocks, "1.29.0", Some(31436), None),

View file

@ -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 {
let constness = match self.kind(id) {
EntryKind::Method(data) => data.decode(self).fn_data.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,
_ => hir::Constness::NotConst,
};

View file

@ -1525,7 +1525,11 @@ impl EncodeContext<'tcx> {
hir::ForeignItemKind::Fn(_, ref names, _) => {
let data = FnData {
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),
};
EntryKind::ForeignFn(self.lazy(data))

View file

@ -2,7 +2,7 @@
//! looking at their MIR. Intrinsics/functions supported here are shared by CTFE
//! and miri.
use syntax::symbol::Symbol;
use syntax_pos::symbol::{sym, Symbol};
use syntax_pos::Span;
use rustc::ty;
use rustc::ty::layout::{LayoutOf, Primitive, Size};
@ -22,7 +22,7 @@ mod caller_location;
mod type_name;
fn numeric_intrinsic<'tcx, Tag>(
name: &str,
name: Symbol,
bits: u128,
kind: Primitive,
) -> InterpResult<'tcx, Scalar<Tag>> {
@ -32,11 +32,11 @@ fn numeric_intrinsic<'tcx, Tag>(
};
let extra = 128 - size.bits() as u128;
let bits_out = match name {
"ctpop" => bits.count_ones() as u128,
"ctlz" => bits.leading_zeros() as u128 - extra,
"cttz" => (bits << extra).trailing_zeros() as u128 - extra,
"bswap" => (bits << extra).swap_bytes(),
"bitreverse" => (bits << extra).reverse_bits(),
sym::ctpop => bits.count_ones() as u128,
sym::ctlz => bits.leading_zeros() as u128 - extra,
sym::cttz => (bits << extra).trailing_zeros() as u128 - extra,
sym::bswap => (bits << extra).swap_bytes(),
sym::bitreverse => (bits << extra).reverse_bits(),
_ => bug!("not a numeric intrinsic: {}", name),
};
Ok(Scalar::from_uint(bits_out, size))
@ -51,9 +51,9 @@ crate fn eval_nullary_intrinsic<'tcx>(
substs: SubstsRef<'tcx>,
) -> InterpResult<'tcx, &'tcx ty::Const<'tcx>> {
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 {
"type_name" => {
sym::type_name => {
let alloc = type_name::alloc_type_name(tcx, tp_ty);
tcx.mk_const(ty::Const {
val: ty::ConstKind::Value(ConstValue::Slice {
@ -64,20 +64,20 @@ crate fn eval_nullary_intrinsic<'tcx>(
ty: tcx.mk_static_str(),
})
},
"needs_drop" => ty::Const::from_bool(tcx, tp_ty.needs_drop(tcx, param_env)),
"size_of" |
"min_align_of" |
"pref_align_of" => {
sym::needs_drop => ty::Const::from_bool(tcx, tp_ty.needs_drop(tcx, param_env)),
sym::size_of |
sym::min_align_of |
sym::pref_align_of => {
let layout = tcx.layout_of(param_env.and(tp_ty)).map_err(|e| err_inval!(Layout(e)))?;
let n = match name {
"pref_align_of" => layout.align.pref.bytes(),
"min_align_of" => layout.align.abi.bytes(),
"size_of" => layout.size.bytes(),
sym::pref_align_of => layout.align.pref.bytes(),
sym::min_align_of => layout.align.abi.bytes(),
sym::size_of => layout.size.bytes(),
_ => bug!(),
};
ty::Const::from_usize(tcx, n)
},
"type_id" => ty::Const::from_bits(
sym::type_id => ty::Const::from_bits(
tcx,
tcx.type_id_hash(tp_ty).into(),
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)>,
) -> InterpResult<'tcx, bool> {
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,
// but `transmute` could lack a return place in case of UB.
let (dest, ret) = match ret {
Some(p) => p,
None => match intrinsic_name {
"transmute" => throw_ub!(Unreachable),
sym::transmute => throw_ub!(Unreachable),
_ => return Ok(false),
}
};
// Keep the patterns in this match ordered the same as the list in
// `src/librustc/ty/constness.rs`
match intrinsic_name {
"caller_location" => {
sym::caller_location => {
let location = self.alloc_caller_location_for_span(span);
self.write_scalar(location.ptr, dest)?;
}
"min_align_of" |
"pref_align_of" |
"needs_drop" |
"size_of" |
"type_id" |
"type_name" => {
sym::min_align_of |
sym::pref_align_of |
sym::needs_drop |
sym::size_of |
sym::type_id |
sym::type_name => {
let gid = GlobalId {
instance,
promoted: None,
@ -129,13 +131,13 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
self.copy_op(val, dest)?;
}
| "ctpop"
| "cttz"
| "cttz_nonzero"
| "ctlz"
| "ctlz_nonzero"
| "bswap"
| "bitreverse" => {
| sym::ctpop
| sym::cttz
| sym::cttz_nonzero
| sym::ctlz
| sym::ctlz_nonzero
| sym::bswap
| sym::bitreverse => {
let ty = substs.type_at(0);
let layout_of = self.layout_of(ty)?;
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,
_ => throw_unsup!(TypeNotPrimitive(ty)),
};
let out_val = if intrinsic_name.ends_with("_nonzero") {
if bits == 0 {
throw_ub_format!("`{}` called on 0", intrinsic_name);
}
numeric_intrinsic(intrinsic_name.trim_end_matches("_nonzero"), bits, kind)?
} else {
numeric_intrinsic(intrinsic_name, bits, kind)?
let (nonzero, intrinsic_name) = match intrinsic_name {
sym::cttz_nonzero => (true, sym::cttz),
sym::ctlz_nonzero => (true, sym::ctlz),
other => (false, other),
};
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)?;
}
| "wrapping_add"
| "wrapping_sub"
| "wrapping_mul"
| "add_with_overflow"
| "sub_with_overflow"
| "mul_with_overflow" => {
| sym::wrapping_add
| sym::wrapping_sub
| sym::wrapping_mul
| sym::add_with_overflow
| sym::sub_with_overflow
| sym::mul_with_overflow => {
let lhs = self.read_immediate(args[0])?;
let rhs = self.read_immediate(args[1])?;
let (bin_op, ignore_overflow) = match intrinsic_name {
"wrapping_add" => (BinOp::Add, true),
"wrapping_sub" => (BinOp::Sub, true),
"wrapping_mul" => (BinOp::Mul, true),
"add_with_overflow" => (BinOp::Add, false),
"sub_with_overflow" => (BinOp::Sub, false),
"mul_with_overflow" => (BinOp::Mul, false),
sym::wrapping_add => (BinOp::Add, true),
sym::wrapping_sub => (BinOp::Sub, true),
sym::wrapping_mul => (BinOp::Mul, true),
sym::add_with_overflow => (BinOp::Add, false),
sym::sub_with_overflow => (BinOp::Sub, false),
sym::mul_with_overflow => (BinOp::Mul, false),
_ => bug!("Already checked for int ops")
};
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)?;
}
}
"saturating_add" | "saturating_sub" => {
sym::saturating_add | sym::saturating_sub => {
let l = self.read_immediate(args[0])?;
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 {
BinOp::Add
} else {
@ -220,12 +223,12 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
};
self.write_scalar(val, dest)?;
}
"unchecked_shl" | "unchecked_shr" => {
sym::unchecked_shl | sym::unchecked_shr => {
let l = self.read_immediate(args[0])?;
let r = self.read_immediate(args[1])?;
let bin_op = match intrinsic_name {
"unchecked_shl" => BinOp::Shl,
"unchecked_shr" => BinOp::Shr,
sym::unchecked_shl => BinOp::Shl,
sym::unchecked_shr => BinOp::Shr,
_ => bug!("Already checked for int ops")
};
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)?;
}
"rotate_left" | "rotate_right" => {
sym::rotate_left | sym::rotate_right => {
// rotate_left: (X << (S % BW)) | (X >> ((BW - S) % BW))
// rotate_right: (X << ((BW - S) % BW)) | (X >> (S % BW))
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 shift_bits = raw_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)
} else {
(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)?;
}
"ptr_offset_from" => {
sym::ptr_offset_from => {
let isize_layout = self.layout_of(self.tcx.types.isize)?;
let a = self.read_immediate(args[0])?.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)?;
}
"simd_insert" => {
sym::simd_insert => {
let index = u64::from(self.read_scalar(args[1])?.to_u32()?);
let elem = args[2];
let input = args[0];
@ -337,7 +340,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
self.copy_op(value, place)?;
}
}
"simd_extract" => {
sym::simd_extract => {
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);
assert!(

View file

@ -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)]
pub struct UnionAccess;
impl NonConstOp for UnionAccess {

View file

@ -8,7 +8,6 @@ use rustc::traits::{self, TraitEngine};
use rustc::ty::cast::CastTy;
use rustc::ty::{self, TyCtxt};
use rustc_index::bit_set::BitSet;
use rustc_target::spec::abi::Abi;
use rustc_error_codes::*;
use syntax::symbol::sym;
use syntax_pos::Span;
@ -202,7 +201,7 @@ impl Validator<'a, 'mir, 'tcx> {
let Item { tcx, body, def_id, const_kind, .. } = *self.item;
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;
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...
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) {
return;
}

View file

@ -2,7 +2,6 @@ use rustc::hir::def_id::DefId;
use rustc::hir;
use rustc::mir::*;
use rustc::ty::{self, Predicate, Ty, TyCtxt, adjustment::{PointerCast}};
use rustc_target::spec::abi;
use std::borrow::Cow;
use syntax_pos::Span;
use syntax::symbol::{sym, Symbol};
@ -356,18 +355,8 @@ fn check_terminator(
} => {
let fn_ty = func.ty(body, tcx);
if let ty::FnDef(def_id, _) = fn_ty.kind {
// some intrinsics are waved through if called inside the
// standard library. Users never need to call them directly
match tcx.fn_sig(def_id).abi() {
abi::Abi::RustIntrinsic => if !is_intrinsic_whitelisted(tcx, def_id) {
if !tcx.is_min_const_fn(def_id) {
return Err((
span,
"can only call a curated list of intrinsics in `min_const_fn`".into(),
))
},
abi::Abi::Rust if tcx.is_min_const_fn(def_id) => {},
abi::Abi::Rust => return Err((
span,
format!(
"can only call other `const fn` within a `const fn`, \
@ -375,14 +364,7 @@ fn check_terminator(
func,
)
.into(),
)),
abi => return Err((
span,
format!(
"cannot call functions with `{}` abi in `min_const_fn`",
abi,
).into(),
)),
));
}
check_operand(tcx, func, span, def_id, body)?;
@ -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,
}
}

View file

@ -121,6 +121,7 @@ symbols! {
abi_vectorcall,
abi_x86_interrupt,
aborts,
add_with_overflow,
advanced_slice_patterns,
adx_target_feature,
alias,
@ -171,7 +172,10 @@ symbols! {
box_patterns,
box_syntax,
braced_empty_structs,
bswap,
bitreverse,
C,
caller_location,
cdylib,
cfg,
cfg_attr,
@ -226,6 +230,11 @@ symbols! {
crate_name,
crate_type,
crate_visibility_modifier,
ctpop,
cttz,
cttz_nonzero,
ctlz,
ctlz_nonzero,
custom_attribute,
custom_derive,
custom_inner_attributes,
@ -431,6 +440,7 @@ symbols! {
member_constraints,
message,
meta,
min_align_of,
min_const_fn,
min_const_unsafe_fn,
mips_target_feature,
@ -440,11 +450,13 @@ symbols! {
more_struct_aliases,
move_val_init,
movbe_target_feature,
mul_with_overflow,
must_use,
naked,
naked_functions,
name,
needs_allocator,
needs_drop,
needs_panic_runtime,
negate_unsigned,
never,
@ -520,6 +532,7 @@ symbols! {
poll_with_tls_context,
powerpc_target_feature,
precise_pointer_size_matching,
pref_align_of,
prelude,
prelude_import,
primitive,
@ -536,6 +549,7 @@ symbols! {
proc_macro_non_items,
proc_macro_path_invoc,
profiler_runtime,
ptr_offset_from,
pub_restricted,
pushpop_unsafe,
quad_precision_float,
@ -571,6 +585,8 @@ symbols! {
Return,
rhs,
rlib,
rotate_left,
rotate_right,
rt,
rtm_target_feature,
rust,
@ -638,14 +654,19 @@ symbols! {
rvalue_static_promotion,
sanitize,
sanitizer_runtime,
saturating_add,
saturating_sub,
_Self,
self_in_typedefs,
self_struct_ctor,
should_panic,
simd,
simd_extract,
simd_ffi,
simd_insert,
since,
size,
size_of,
slice_patterns,
slicing_syntax,
soft,
@ -673,6 +694,7 @@ symbols! {
structural_match,
struct_variant,
sty,
sub_with_overflow,
suggestion,
target_feature,
target_has_atomic,
@ -708,6 +730,8 @@ symbols! {
Ty,
ty,
type_alias_impl_trait,
type_id,
type_name,
TyCtxt,
TyKind,
type_alias_enum_variants,
@ -720,6 +744,8 @@ symbols! {
u64,
u8,
unboxed_closures,
unchecked_shl,
unchecked_shr,
underscore_const_names,
underscore_imports,
underscore_lifetimes,
@ -753,6 +779,9 @@ symbols! {
while_let,
windows,
windows_subsystem,
wrapping_add,
wrapping_sub,
wrapping_mul,
Yield,
}
}

View file

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

View file

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

View file

@ -7,7 +7,7 @@ extern "C" {
const extern fn bar() {
unsafe {
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() {
unsafe {
regular();
//~^ ERROR: cannot call functions with `"C"` abi in `min_const_fn`
//~^ ERROR: can only call other `const fn` within a `const fn`
}
}

View file

@ -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
|
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
= 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
|
LL | regular();

View file

@ -4,6 +4,6 @@ use std::mem;
struct Foo(u32);
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() {}

View file

@ -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
|
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
error: aborting due to previous error
For more information about this error, try `rustc --explain E0658`.