Rollup merge of #73778 - nbdd0121:const_likely, r=oli-obk
Make `likely` and `unlikely` const, gated by feature `const_unlikely` This PR also contains a fix to allow `#[allow_internal_unstable]` to work properly with `#[rustc_const_unstable]`. cc @RalfJung @nagisa r? @oli-obk
This commit is contained in:
commit
ec41d01d4f
6 changed files with 47 additions and 6 deletions
|
@ -952,6 +952,7 @@ extern "rust-intrinsic" {
|
|||
/// Any use other than with `if` statements will probably not have an effect.
|
||||
///
|
||||
/// This intrinsic does not have a stable counterpart.
|
||||
#[rustc_const_unstable(feature = "const_likely", issue = "none")]
|
||||
pub fn likely(b: bool) -> bool;
|
||||
|
||||
/// Hints to the compiler that branch condition is likely to be false.
|
||||
|
@ -960,6 +961,7 @@ extern "rust-intrinsic" {
|
|||
/// Any use other than with `if` statements will probably not have an effect.
|
||||
///
|
||||
/// This intrinsic does not have a stable counterpart.
|
||||
#[rustc_const_unstable(feature = "const_likely", issue = "none")]
|
||||
pub fn unlikely(b: bool) -> bool;
|
||||
|
||||
/// Executes a breakpoint trap, for inspection by a debugger.
|
||||
|
|
|
@ -92,6 +92,7 @@
|
|||
#![feature(const_slice_from_raw_parts)]
|
||||
#![feature(const_slice_ptr_len)]
|
||||
#![feature(const_type_name)]
|
||||
#![feature(const_likely)]
|
||||
#![feature(custom_inner_attributes)]
|
||||
#![feature(decl_macro)]
|
||||
#![feature(doc_cfg)]
|
||||
|
|
|
@ -409,6 +409,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
);
|
||||
self.copy_op(self.operand_index(args[0], index)?, dest)?;
|
||||
}
|
||||
sym::likely | sym::unlikely => {
|
||||
// These just return their argument
|
||||
self.copy_op(args[0], dest)?;
|
||||
}
|
||||
// FIXME(#73156): Handle source code coverage in const eval
|
||||
sym::count_code_region => (),
|
||||
_ => return Ok(false),
|
||||
|
|
|
@ -531,9 +531,12 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
|
|||
if is_lang_panic_fn(self.tcx, def_id) {
|
||||
self.check_op(ops::Panic);
|
||||
} else if let Some(feature) = is_unstable_const_fn(self.tcx, def_id) {
|
||||
// Exempt unstable const fns inside of macros with
|
||||
// Exempt unstable const fns inside of macros or functions with
|
||||
// `#[allow_internal_unstable]`.
|
||||
if !self.span.allows_unstable(feature) {
|
||||
use crate::transform::qualify_min_const_fn::lib_feature_allowed;
|
||||
if !self.span.allows_unstable(feature)
|
||||
&& !lib_feature_allowed(self.tcx, self.def_id, feature)
|
||||
{
|
||||
self.check_op(ops::FnCallUnstable(def_id, feature));
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -328,6 +328,26 @@ fn feature_allowed(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: Symbol) -> bo
|
|||
.map_or(false, |mut features| features.any(|name| name == feature_gate))
|
||||
}
|
||||
|
||||
/// Returns `true` if the given library feature gate is allowed within the function with the given `DefId`.
|
||||
pub fn lib_feature_allowed(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: Symbol) -> bool {
|
||||
// All features require that the corresponding gate be enabled,
|
||||
// even if the function has `#[allow_internal_unstable(the_gate)]`.
|
||||
if !tcx.features().declared_lib_features.iter().any(|&(sym, _)| sym == feature_gate) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If this crate is not using stability attributes, or this function is not claiming to be a
|
||||
// stable `const fn`, that is all that is required.
|
||||
if !tcx.features().staged_api || tcx.has_attr(def_id, sym::rustc_const_unstable) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// However, we cannot allow stable `const fn`s to use unstable features without an explicit
|
||||
// opt-in via `allow_internal_unstable`.
|
||||
attr::allow_internal_unstable(&tcx.get_attrs(def_id), &tcx.sess.diagnostic())
|
||||
.map_or(false, |mut features| features.any(|name| name == feature_gate))
|
||||
}
|
||||
|
||||
fn check_terminator(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &'a Body<'tcx>,
|
||||
|
@ -367,8 +387,17 @@ fn check_terminator(
|
|||
fn_span: _,
|
||||
} => {
|
||||
let fn_ty = func.ty(body, tcx);
|
||||
if let ty::FnDef(def_id, _) = fn_ty.kind {
|
||||
if !crate::const_eval::is_min_const_fn(tcx, def_id) {
|
||||
if let ty::FnDef(fn_def_id, _) = fn_ty.kind {
|
||||
// Allow unstable const if we opt in by using #[allow_internal_unstable]
|
||||
// on function or macro declaration.
|
||||
if !crate::const_eval::is_min_const_fn(tcx, fn_def_id)
|
||||
&& !crate::const_eval::is_unstable_const_fn(tcx, fn_def_id)
|
||||
.map(|feature| {
|
||||
span.allows_unstable(feature)
|
||||
|| lib_feature_allowed(tcx, def_id, feature)
|
||||
})
|
||||
.unwrap_or(false)
|
||||
{
|
||||
return Err((
|
||||
span,
|
||||
format!(
|
||||
|
@ -380,10 +409,10 @@ fn check_terminator(
|
|||
));
|
||||
}
|
||||
|
||||
check_operand(tcx, func, span, def_id, body)?;
|
||||
check_operand(tcx, func, span, fn_def_id, body)?;
|
||||
|
||||
for arg in args {
|
||||
check_operand(tcx, arg, span, def_id, body)?;
|
||||
check_operand(tcx, arg, span, fn_def_id, body)?;
|
||||
}
|
||||
Ok(())
|
||||
} else {
|
||||
|
|
|
@ -427,6 +427,7 @@ symbols! {
|
|||
lhs,
|
||||
lib,
|
||||
lifetime,
|
||||
likely,
|
||||
line,
|
||||
link,
|
||||
linkage,
|
||||
|
@ -813,6 +814,7 @@ symbols! {
|
|||
underscore_lifetimes,
|
||||
uniform_paths,
|
||||
universal_impl_trait,
|
||||
unlikely,
|
||||
unmarked_api,
|
||||
unreachable_code,
|
||||
unrestricted_attribute_tokens,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue