From 224bc052564117abfb8716772779ade221133395 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Fri, 26 Jun 2020 21:05:39 +0100 Subject: [PATCH 1/4] Fix allow_internal_unstable with rustc_const_unstable --- .../transform/check_consts/validation.rs | 7 +++++-- .../transform/qualify_min_const_fn.rs | 18 +++++++++++++----- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs index d263bf12e8868..80257260f0183 100644 --- a/src/librustc_mir/transform/check_consts/validation.rs +++ b/src/librustc_mir/transform/check_consts/validation.rs @@ -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::feature_allowed; + if !self.span.allows_unstable(feature) + && !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 caf6c7715a9e1..6f252ad4ed535 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -315,7 +315,7 @@ fn check_place( } /// Returns `true` if the given feature gate is allowed within the function with the given `DefId`. -fn feature_allowed(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: Symbol) -> bool { +pub fn 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().enabled(feature_gate) { @@ -377,8 +377,16 @@ 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) || feature_allowed(tcx, def_id, feature) + }) + .unwrap_or(false) + { return Err(( span, format!( @@ -390,10 +398,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 { From fc239e82fe1ef91632dfa858487d89141aaab7a7 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Fri, 26 Jun 2020 13:19:50 +0100 Subject: [PATCH 2/4] Make `likely` and `unlikely` const They are gated by internal feature gate const_likely --- src/libcore/intrinsics.rs | 2 ++ src/libcore/lib.rs | 1 + src/librustc_mir/interpret/intrinsics.rs | 5 +++++ src/librustc_span/symbol.rs | 2 ++ 4 files changed, 10 insertions(+) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 2298958b88101..da174299fb9af 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 4eb2fdbd07868..412d323b283a3 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 6ac1e6be03674..52cb700c3d58f 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -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)?; + } // FIXME(#73156): Handle source code coverage in const eval sym::count_code_region => (), _ => return Ok(false), diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs index fa1368b104c7e..3e62486feb95e 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, From 779b05d16a38fec347a874210e2ae54579a8f5c1 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Fri, 26 Jun 2020 23:33:35 +0100 Subject: [PATCH 3/4] Fix ICE for lib features --- .../transform/check_consts/validation.rs | 4 +-- .../transform/qualify_min_const_fn.rs | 25 +++++++++++++++++-- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs index 80257260f0183..bd9d33e67f8fb 100644 --- a/src/librustc_mir/transform/check_consts/validation.rs +++ b/src/librustc_mir/transform/check_consts/validation.rs @@ -550,9 +550,9 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { } else if let Some(feature) = is_unstable_const_fn(self.tcx, def_id) { // Exempt unstable const fns inside of macros or functions with // `#[allow_internal_unstable]`. - use crate::transform::qualify_min_const_fn::feature_allowed; + use crate::transform::qualify_min_const_fn::lib_feature_allowed; if !self.span.allows_unstable(feature) - && !feature_allowed(self.tcx, self.def_id, feature) + && !lib_feature_allowed(self.tcx, self.def_id, feature) { self.check_op(ops::FnCallUnstable(def_id, feature)); } diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index 6f252ad4ed535..7c54acf2163cc 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -315,7 +315,7 @@ fn check_place( } /// Returns `true` if the given feature gate is allowed within the function with the given `DefId`. -pub fn feature_allowed(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: Symbol) -> bool { +fn 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().enabled(feature_gate) { @@ -334,6 +334,26 @@ pub fn feature_allowed(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: Symbol) - .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>, @@ -383,7 +403,8 @@ fn check_terminator( 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) || feature_allowed(tcx, def_id, feature) + span.allows_unstable(feature) + || lib_feature_allowed(tcx, def_id, feature) }) .unwrap_or(false) { From 8b43012453de32d4e429c923171131f938d3ead8 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sat, 27 Jun 2020 18:24:46 +0100 Subject: [PATCH 4/4] Update src/librustc_mir/interpret/intrinsics.rs Co-authored-by: Oliver Scherer --- src/librustc_mir/interpret/intrinsics.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 52cb700c3d58f..983dc1dc81955 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -401,8 +401,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } sym::likely | sym::unlikely => { // These just return their argument - let a = self.read_immediate(args[0])?; - self.write_immediate(*a, dest)?; + self.copy_op(args[0], dest)?; } // FIXME(#73156): Handle source code coverage in const eval sym::count_code_region => (),