Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make likely and unlikely const, gated by feature const_unlikely #73778

Merged
merged 4 commits into from
Jul 1, 2020
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/libcore/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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.
Expand Down
1 change: 1 addition & 0 deletions src/libcore/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
5 changes: 5 additions & 0 deletions src/librustc_mir/interpret/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,11 @@ 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
let a = self.read_immediate(args[0])?;
self.write_immediate(*a, dest)?;
nbdd0121 marked this conversation as resolved.
Show resolved Hide resolved
}
// FIXME(#73156): Handle source code coverage in const eval
sym::count_code_region => (),
_ => return Ok(false),
Expand Down
7 changes: 5 additions & 2 deletions src/librustc_mir/transform/check_consts/validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -548,9 +548,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 {
Expand Down
37 changes: 33 additions & 4 deletions src/librustc_mir/transform/qualify_min_const_fn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,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>,
Expand Down Expand Up @@ -377,8 +397,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!(
Expand All @@ -390,10 +419,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 {
Expand Down
2 changes: 2 additions & 0 deletions src/librustc_span/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,7 @@ symbols! {
lhs,
lib,
lifetime,
likely,
line,
link,
linkage,
Expand Down Expand Up @@ -813,6 +814,7 @@ symbols! {
underscore_lifetimes,
uniform_paths,
universal_impl_trait,
unlikely,
unmarked_api,
unreachable_code,
unrestricted_attribute_tokens,
Expand Down