about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_mir/src/transform/check_consts/ops.rs26
-rw-r--r--compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs11
-rw-r--r--compiler/rustc_mir/src/transform/check_consts/validation.rs2
3 files changed, 33 insertions, 6 deletions
diff --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_mir/src/transform/check_consts/ops.rs
index 4af355310ae..032cbc23a3f 100644
--- a/compiler/rustc_mir/src/transform/check_consts/ops.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/ops.rs
@@ -1,6 +1,6 @@
 //! Concrete error types for all operations which may be invalid in a certain const context.
 
-use rustc_errors::struct_span_err;
+use rustc_errors::{struct_span_err, Applicability};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_session::config::nightly_options;
@@ -16,7 +16,29 @@ pub fn non_const<O: NonConstOp>(ccx: &ConstCx<'_, '_>, op: O, span: Span) {
 
     let gate = match op.status_in_item(ccx) {
         Status::Allowed => return,
-        Status::Unstable(gate) if ccx.tcx.features().enabled(gate) => return,
+
+        Status::Unstable(gate) if ccx.tcx.features().enabled(gate) => {
+            let unstable_in_stable = ccx.const_kind() == hir::ConstContext::ConstFn
+                && ccx.tcx.features().enabled(sym::staged_api)
+                && !ccx.tcx.has_attr(ccx.def_id.to_def_id(), sym::rustc_const_unstable)
+                && !super::allow_internal_unstable(ccx.tcx, ccx.def_id.to_def_id(), gate);
+
+            if unstable_in_stable {
+                ccx.tcx.sess
+                    .struct_span_err(span, &format!("`#[feature({})]` cannot be depended on in a const-stable function", gate.as_str()))
+                    .span_suggestion(
+                        ccx.body.span,
+                        "if it is not part of the public API, make this function unstably const",
+                        concat!(r#"#[rustc_const_unstable(feature = "...", issue = "...")]"#, '\n').to_owned(),
+                        Applicability::HasPlaceholders,
+                    )
+                    .help("otherwise `#[allow_internal_unstable]` can be used to bypass stability checks")
+                    .emit();
+            }
+
+            return;
+        }
+
         Status::Unstable(gate) => Some(gate),
         Status::Forbidden => None,
     };
diff --git a/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs b/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs
index a2e5c905612..0228f2d7de0 100644
--- a/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs
@@ -2,7 +2,7 @@ use rustc_hir::def_id::LocalDefId;
 use rustc_middle::mir::visit::Visitor;
 use rustc_middle::mir::{self, BasicBlock, Location};
 use rustc_middle::ty::TyCtxt;
-use rustc_span::Span;
+use rustc_span::{sym, Span};
 
 use super::ops;
 use super::qualifs::{NeedsDrop, Qualif};
@@ -11,7 +11,12 @@ use super::ConstCx;
 
 /// Returns `true` if we should use the more precise live drop checker that runs after drop
 /// elaboration.
-pub fn checking_enabled(tcx: TyCtxt<'tcx>) -> bool {
+pub fn checking_enabled(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool {
+    // Const-stable functions must always use the stable live drop checker.
+    if tcx.features().staged_api && !tcx.has_attr(def_id.to_def_id(), sym::rustc_const_unstable) {
+        return false;
+    }
+
     tcx.features().const_precise_live_drops
 }
 
@@ -25,7 +30,7 @@ pub fn check_live_drops(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &mir::Body<
         return;
     }
 
-    if !checking_enabled(tcx) {
+    if !checking_enabled(tcx, def_id) {
         return;
     }
 
diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs
index ebba7f29663..0501302b761 100644
--- a/compiler/rustc_mir/src/transform/check_consts/validation.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs
@@ -551,7 +551,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
             | TerminatorKind::DropAndReplace { place: dropped_place, .. } => {
                 // If we are checking live drops after drop-elaboration, don't emit duplicate
                 // errors here.
-                if super::post_drop_elaboration::checking_enabled(self.tcx) {
+                if super::post_drop_elaboration::checking_enabled(self.tcx, self.def_id) {
                     return;
                 }