about summary refs log tree commit diff
diff options
context:
space:
mode:
authorManish Goregaokar <manishsmail@gmail.com>2020-07-01 07:42:52 -0700
committerGitHub <noreply@github.com>2020-07-01 07:42:52 -0700
commitec41d01d4f7c668a75eff1ba724b8a67c7ec90b4 (patch)
tree8418d77e0d1dcb6cf2dfba9c1a951f7a3b7e0a60
parentd6bee55855093d86c7e110116beebb369cd89654 (diff)
parent8b43012453de32d4e429c923171131f938d3ead8 (diff)
downloadrust-ec41d01d4f7c668a75eff1ba724b8a67c7ec90b4.tar.gz
rust-ec41d01d4f7c668a75eff1ba724b8a67c7ec90b4.zip
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
-rw-r--r--src/libcore/intrinsics.rs2
-rw-r--r--src/libcore/lib.rs1
-rw-r--r--src/librustc_mir/interpret/intrinsics.rs4
-rw-r--r--src/librustc_mir/transform/check_consts/validation.rs7
-rw-r--r--src/librustc_mir/transform/qualify_min_const_fn.rs37
-rw-r--r--src/librustc_span/symbol.rs2
6 files changed, 47 insertions, 6 deletions
diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs
index 5d090187591..57ffed19c00 100644
--- a/src/libcore/intrinsics.rs
+++ b/src/libcore/intrinsics.rs
@@ -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.
diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs
index b732dacae1c..63ddd97eed3 100644
--- a/src/libcore/lib.rs
+++ b/src/libcore/lib.rs
@@ -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)]
diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs
index 88ba28dab82..01eb2d0b8e2 100644
--- a/src/librustc_mir/interpret/intrinsics.rs
+++ b/src/librustc_mir/interpret/intrinsics.rs
@@ -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),
diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs
index ca1f0aecd04..f00fc96e591 100644
--- a/src/librustc_mir/transform/check_consts/validation.rs
+++ b/src/librustc_mir/transform/check_consts/validation.rs
@@ -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 {
diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs
index 5a3663384fb..2f5257080cd 100644
--- a/src/librustc_mir/transform/qualify_min_const_fn.rs
+++ b/src/librustc_mir/transform/qualify_min_const_fn.rs
@@ -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 {
diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs
index 857734037af..e2f0d0b94c4 100644
--- a/src/librustc_span/symbol.rs
+++ b/src/librustc_span/symbol.rs
@@ -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,