about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-05-22 06:47:36 +0000
committerbors <bors@rust-lang.org>2022-05-22 06:47:36 +0000
commitacfd327fd4e3a302ebb0a077f422a527a7935333 (patch)
tree0fc26d507911459b9a9ac91b65c4f8cbe10a5ba3
parentbb5e6c984de2fbabba37655551f4bab16fbd9e5e (diff)
parentf9c4f2b7ad431c6658682724a057b4a36920fdb4 (diff)
downloadrust-acfd327fd4e3a302ebb0a077f422a527a7935333.tar.gz
rust-acfd327fd4e3a302ebb0a077f422a527a7935333.zip
Auto merge of #97177 - oli-obk:const-stability, r=davidtwco
Implement proper stability check for const impl Trait, fall back to unstable const when undeclared

Continuation of #93960

`@jhpratt` it looks to me like the test was simply not testing for the failure you were looking for? Your checks actually do the right thing for const traits?
-rw-r--r--compiler/rustc_attr/src/builtin.rs20
-rw-r--r--compiler/rustc_const_eval/src/const_eval/fn_queries.rs2
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs14
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/mod.rs43
-rw-r--r--compiler/rustc_middle/src/ty/context.rs17
-rw-r--r--compiler/rustc_passes/src/stability.rs43
-rw-r--r--src/librustdoc/clean/inline.rs4
-rw-r--r--src/librustdoc/clean/types.rs2
-rw-r--r--src/librustdoc/html/render/print_item.rs5
-rw-r--r--src/test/ui/consts/rustc-impl-const-stability.rs7
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/auxiliary/staged-api.rs7
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/stability.rs45
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/stability.stderr19
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/staged-api-user-crate.rs16
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/staged-api-user-crate.stderr11
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/staged-api.rs52
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/staged-api.stable.stderr25
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/staged-api.staged.stderr10
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/staged-api.stock.stderr18
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/staged-api.unstable.stderr42
-rw-r--r--src/test/ui/stability-attribute/missing-const-stability.rs14
-rw-r--r--src/test/ui/stability-attribute/missing-const-stability.stderr11
22 files changed, 259 insertions, 168 deletions
diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index 3d4bd222715..2704cb8d785 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -101,6 +101,16 @@ pub struct Stability {
     pub feature: Symbol,
 }
 
+impl Stability {
+    pub fn is_unstable(&self) -> bool {
+        self.level.is_unstable()
+    }
+
+    pub fn is_stable(&self) -> bool {
+        self.level.is_stable()
+    }
+}
+
 /// Represents the `#[rustc_const_unstable]` and `#[rustc_const_stable]` attributes.
 #[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
 #[derive(HashStable_Generic)]
@@ -111,6 +121,16 @@ pub struct ConstStability {
     pub promotable: bool,
 }
 
+impl ConstStability {
+    pub fn is_const_unstable(&self) -> bool {
+        self.level.is_unstable()
+    }
+
+    pub fn is_const_stable(&self) -> bool {
+        self.level.is_stable()
+    }
+}
+
 /// The available stability levels.
 #[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
 #[derive(HashStable_Generic)]
diff --git a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
index 777f4393458..d6f62062d1f 100644
--- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
@@ -9,7 +9,7 @@ use rustc_span::symbol::Symbol;
 pub fn is_unstable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Symbol> {
     if tcx.is_const_fn_raw(def_id) {
         let const_stab = tcx.lookup_const_stability(def_id)?;
-        if const_stab.level.is_unstable() { Some(const_stab.feature) } else { None }
+        if const_stab.is_const_unstable() { Some(const_stab.feature) } else { None }
     } else {
         None
     }
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
index 1104bbf4716..2c669dd6d9a 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -229,18 +229,6 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
 
         // The local type and predicate checks are not free and only relevant for `const fn`s.
         if self.const_kind() == hir::ConstContext::ConstFn {
-            // Prevent const trait methods from being annotated as `stable`.
-            // FIXME: Do this as part of stability checking.
-            if self.is_const_stable_const_fn() {
-                if crate::const_eval::is_parent_const_impl_raw(tcx, def_id) {
-                    self.ccx
-                        .tcx
-                        .sess
-                        .struct_span_err(self.span, "trait methods cannot be stable const fn")
-                        .emit();
-                }
-            }
-
             for (idx, local) in body.local_decls.iter_enumerated() {
                 // Handle the return place below.
                 if idx == RETURN_PLACE || local.internal {
@@ -944,7 +932,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                 // have no `rustc_const_stable` attributes to be const-unstable as well. This
                 // should be fixed later.
                 let callee_is_unstable_unmarked = tcx.lookup_const_stability(callee).is_none()
-                    && tcx.lookup_stability(callee).map_or(false, |s| s.level.is_unstable());
+                    && tcx.lookup_stability(callee).map_or(false, |s| s.is_unstable());
                 if callee_is_unstable_unmarked {
                     trace!("callee_is_unstable_unmarked");
                     // We do not use `const` modifiers for intrinsic "functions", as intrinsics are
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs
index 23e2afae791..0f79fe5513d 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs
@@ -84,8 +84,6 @@ pub fn rustc_allow_const_fn_unstable(
 // functions are subject to more stringent restrictions than "const-unstable" functions: They
 // cannot use unstable features and can only call other "const-stable" functions.
 pub fn is_const_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
-    use attr::{ConstStability, Stability, StabilityLevel};
-
     // A default body marked const is not const-stable because const
     // trait fns currently cannot be const-stable. We shouldn't
     // restrict default bodies to only call const-stable functions.
@@ -96,22 +94,39 @@ pub fn is_const_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
     // Const-stability is only relevant for `const fn`.
     assert!(tcx.is_const_fn_raw(def_id));
 
-    // Functions with `#[rustc_const_unstable]` are const-unstable.
+    // A function is only const-stable if it has `#[rustc_const_stable]` or it the trait it belongs
+    // to is const-stable.
     match tcx.lookup_const_stability(def_id) {
-        Some(ConstStability { level: StabilityLevel::Unstable { .. }, .. }) => return false,
-        Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => return true,
-        None => {}
+        Some(stab) => stab.is_const_stable(),
+        None if is_parent_const_stable_trait(tcx, def_id) => {
+            // Remove this when `#![feature(const_trait_impl)]` is stabilized,
+            // returning `true` unconditionally.
+            tcx.sess.delay_span_bug(
+                tcx.def_span(def_id),
+                "trait implementations cannot be const stable yet",
+            );
+            true
+        }
+        None => false, // By default, items are not const stable.
     }
+}
+
+fn is_parent_const_stable_trait(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
+    let local_def_id = def_id.expect_local();
+    let hir_id = tcx.local_def_id_to_hir_id(local_def_id);
+
+    let Some(parent) = tcx.hir().find_parent_node(hir_id) else { return false };
+    let parent_def = tcx.hir().get(parent);
 
-    // Functions with `#[unstable]` are const-unstable.
-    //
-    // FIXME(ecstaticmorse): We should keep const-stability attributes wholly separate from normal stability
-    // attributes. `#[unstable]` should be irrelevant.
-    if let Some(Stability { level: StabilityLevel::Unstable { .. }, .. }) =
-        tcx.lookup_stability(def_id)
-    {
+    if !matches!(
+        parent_def,
+        hir::Node::Item(hir::Item {
+            kind: hir::ItemKind::Impl(hir::Impl { constness: hir::Constness::Const, .. }),
+            ..
+        })
+    ) {
         return false;
     }
 
-    true
+    tcx.lookup_const_stability(parent.owner).map_or(false, |stab| stab.is_const_stable())
 }
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 31e131182cc..1b466910633 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -2791,7 +2791,7 @@ impl<'tcx> TyCtxt<'tcx> {
     pub fn is_const_fn(self, def_id: DefId) -> bool {
         if self.is_const_fn_raw(def_id) {
             match self.lookup_const_stability(def_id) {
-                Some(stability) if stability.level.is_unstable() => {
+                Some(stability) if stability.is_const_unstable() => {
                     // has a `rustc_const_unstable` attribute, check whether the user enabled the
                     // corresponding feature gate.
                     self.features()
@@ -2808,6 +2808,21 @@ impl<'tcx> TyCtxt<'tcx> {
             false
         }
     }
+
+    /// Whether the trait impl is marked const. This does not consider stability or feature gates.
+    pub fn is_const_trait_impl_raw(self, def_id: DefId) -> bool {
+        let Some(local_def_id) = def_id.as_local() else { return false };
+        let hir_id = self.local_def_id_to_hir_id(local_def_id);
+        let node = self.hir().get(hir_id);
+
+        matches!(
+            node,
+            hir::Node::Item(hir::Item {
+                kind: hir::ItemKind::Impl(hir::Impl { constness: hir::Constness::Const, .. }),
+                ..
+            })
+        )
+    }
 }
 
 impl<'tcx> TyCtxtAt<'tcx> {
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index 58195fce281..70cb1f2a281 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -147,7 +147,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
             // Propagate unstability.  This can happen even for non-staged-api crates in case
             // -Zforce-unstable-if-unmarked is set.
             if let Some(stab) = self.parent_stab {
-                if inherit_deprecation.yes() && stab.level.is_unstable() {
+                if inherit_deprecation.yes() && stab.is_unstable() {
                     self.index.stab_map.insert(def_id, stab);
                 }
             }
@@ -190,7 +190,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
         if const_stab.is_none() {
             debug!("annotate: const_stab not found, parent = {:?}", self.parent_const_stab);
             if let Some(parent) = self.parent_const_stab {
-                if parent.level.is_unstable() {
+                if parent.is_const_unstable() {
                     self.index.const_stab_map.insert(def_id, parent);
                 }
             }
@@ -272,9 +272,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
         if stab.is_none() {
             debug!("annotate: stab not found, parent = {:?}", self.parent_stab);
             if let Some(stab) = self.parent_stab {
-                if inherit_deprecation.yes() && stab.level.is_unstable()
-                    || inherit_from_parent.yes()
-                {
+                if inherit_deprecation.yes() && stab.is_unstable() || inherit_from_parent.yes() {
                     self.index.stab_map.insert(def_id, stab);
                 }
             }
@@ -532,7 +530,8 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> {
             return;
         }
 
-        let is_const = self.tcx.is_const_fn(def_id.to_def_id());
+        let is_const = self.tcx.is_const_fn(def_id.to_def_id())
+            || self.tcx.is_const_trait_impl_raw(def_id.to_def_id());
         let is_stable = self
             .tcx
             .lookup_stability(def_id)
@@ -710,16 +709,23 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
             // For implementations of traits, check the stability of each item
             // individually as it's possible to have a stable trait with unstable
             // items.
-            hir::ItemKind::Impl(hir::Impl { of_trait: Some(ref t), self_ty, items, .. }) => {
-                if self.tcx.features().staged_api {
+            hir::ItemKind::Impl(hir::Impl {
+                of_trait: Some(ref t),
+                self_ty,
+                items,
+                constness,
+                ..
+            }) => {
+                let features = self.tcx.features();
+                if features.staged_api {
+                    let attrs = self.tcx.hir().attrs(item.hir_id());
+                    let (stab, const_stab) = attr::find_stability(&self.tcx.sess, attrs, item.span);
+
                     // If this impl block has an #[unstable] attribute, give an
                     // error if all involved types and traits are stable, because
                     // it will have no effect.
                     // See: https://github.com/rust-lang/rust/issues/55436
-                    let attrs = self.tcx.hir().attrs(item.hir_id());
-                    if let (Some((Stability { level: attr::Unstable { .. }, .. }, span)), _) =
-                        attr::find_stability(&self.tcx.sess, attrs, item.span)
-                    {
+                    if let Some((Stability { level: attr::Unstable { .. }, .. }, span)) = stab {
                         let mut c = CheckTraitImplStable { tcx: self.tcx, fully_stable: true };
                         c.visit_ty(self_ty);
                         c.visit_trait_ref(t);
@@ -735,6 +741,19 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
                             );
                         }
                     }
+
+                    // `#![feature(const_trait_impl)]` is unstable, so any impl declared stable
+                    // needs to have an error emitted.
+                    if features.const_trait_impl
+                        && *constness == hir::Constness::Const
+                        && const_stab.map_or(false, |(stab, _)| stab.is_const_stable())
+                    {
+                        self.tcx
+                            .sess
+                            .struct_span_err(item.span, "trait implementations cannot be const stable yet")
+                            .note("see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information")
+                            .emit();
+                    }
                 }
 
                 for impl_item_ref in *items {
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 1b6658bb4ca..e7b966758d6 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -344,7 +344,7 @@ pub(crate) fn build_impl(
             }
 
             if let Some(stab) = tcx.lookup_stability(did) {
-                if stab.level.is_unstable() && stab.feature == sym::rustc_private {
+                if stab.is_unstable() && stab.feature == sym::rustc_private {
                     return;
                 }
             }
@@ -373,7 +373,7 @@ pub(crate) fn build_impl(
             }
 
             if let Some(stab) = tcx.lookup_stability(did) {
-                if stab.level.is_unstable() && stab.feature == sym::rustc_private {
+                if stab.is_unstable() && stab.feature == sym::rustc_private {
                     return;
                 }
             }
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 3123ece3773..a832d03a501 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -632,7 +632,7 @@ impl Item {
         self.stability(tcx).as_ref().and_then(|s| {
             let mut classes = Vec::with_capacity(2);
 
-            if s.level.is_unstable() {
+            if s.is_unstable() {
                 classes.push("unstable");
             }
 
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index 12e6115e6fe..2c0b8d7bde1 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -445,10 +445,7 @@ fn extra_info_tags(item: &clean::Item, parent: &clean::Item, tcx: TyCtxt<'_>) ->
 
     // The "rustc_private" crates are permanently unstable so it makes no sense
     // to render "unstable" everywhere.
-    if item
-        .stability(tcx)
-        .as_ref()
-        .map(|s| s.level.is_unstable() && s.feature != sym::rustc_private)
+    if item.stability(tcx).as_ref().map(|s| s.is_unstable() && s.feature != sym::rustc_private)
         == Some(true)
     {
         tags += &tag_html("unstable", "", "Experimental");
diff --git a/src/test/ui/consts/rustc-impl-const-stability.rs b/src/test/ui/consts/rustc-impl-const-stability.rs
index e3fda57548e..0c18efa0a02 100644
--- a/src/test/ui/consts/rustc-impl-const-stability.rs
+++ b/src/test/ui/consts/rustc-impl-const-stability.rs
@@ -1,19 +1,18 @@
-// build-pass
+// check-pass
 
 #![crate_type = "lib"]
 #![feature(staged_api)]
 #![feature(const_trait_impl)]
 #![stable(feature = "foo", since = "1.0.0")]
 
-
 #[stable(feature = "potato", since = "1.27.0")]
 pub struct Data {
-    _data: u128
+    _data: u128,
 }
 
 #[stable(feature = "potato", since = "1.27.0")]
+#[rustc_const_unstable(feature = "data_foo", issue = "none")]
 impl const Default for Data {
-    #[rustc_const_unstable(feature = "data_foo", issue = "none")]
     fn default() -> Data {
         Data { _data: 42 }
     }
diff --git a/src/test/ui/rfc-2632-const-trait-impl/auxiliary/staged-api.rs b/src/test/ui/rfc-2632-const-trait-impl/auxiliary/staged-api.rs
index 80e61ab0a9e..19e9006094b 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/auxiliary/staged-api.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/auxiliary/staged-api.rs
@@ -1,5 +1,4 @@
 #![feature(const_trait_impl)]
-
 #![feature(staged_api)]
 #![stable(feature = "rust1", since = "1.0.0")]
 
@@ -13,9 +12,7 @@ pub trait MyTrait {
 pub struct Unstable;
 
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "staged", issue = "none")]
+#[rustc_const_unstable(feature = "unstable", issue = "none")]
 impl const MyTrait for Unstable {
-    fn func() {
-
-    }
+    fn func() {}
 }
diff --git a/src/test/ui/rfc-2632-const-trait-impl/stability.rs b/src/test/ui/rfc-2632-const-trait-impl/stability.rs
deleted file mode 100644
index 906956f5eba..00000000000
--- a/src/test/ui/rfc-2632-const-trait-impl/stability.rs
+++ /dev/null
@@ -1,45 +0,0 @@
-#![feature(allow_internal_unstable)]
-#![feature(const_add)]
-#![feature(const_trait_impl)]
-#![feature(staged_api)]
-#![stable(feature = "rust1", since = "1.0.0")]
-
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct Int(i32);
-
-#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
-impl const std::ops::Sub for Int {
-    type Output = Self;
-
-    fn sub(self, rhs: Self) -> Self {
-        //~^ ERROR trait methods cannot be stable const fn
-        Int(self.0 - rhs.0)
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_add", issue = "none")]
-impl const std::ops::Add for Int {
-    type Output = Self;
-
-    fn add(self, rhs: Self) -> Self {
-        Int(self.0 + rhs.0)
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
-pub const fn foo() -> Int {
-    Int(1i32) + Int(2i32)
-    //~^ ERROR not yet stable as a const fn
-}
-
-// ok
-#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "bar", issue = "none")]
-pub const fn bar() -> Int {
-    Int(1i32) + Int(2i32)
-}
-
-fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/stability.stderr b/src/test/ui/rfc-2632-const-trait-impl/stability.stderr
deleted file mode 100644
index 7473b801cce..00000000000
--- a/src/test/ui/rfc-2632-const-trait-impl/stability.stderr
+++ /dev/null
@@ -1,19 +0,0 @@
-error: trait methods cannot be stable const fn
-  --> $DIR/stability.rs:15:5
-   |
-LL | /     fn sub(self, rhs: Self) -> Self {
-LL | |
-LL | |         Int(self.0 - rhs.0)
-LL | |     }
-   | |_____^
-
-error: `<Int as Add>::add` is not yet stable as a const fn
-  --> $DIR/stability.rs:34:5
-   |
-LL |     Int(1i32) + Int(2i32)
-   |     ^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: const-stable functions can only call other const-stable functions
-
-error: aborting due to 2 previous errors
-
diff --git a/src/test/ui/rfc-2632-const-trait-impl/staged-api-user-crate.rs b/src/test/ui/rfc-2632-const-trait-impl/staged-api-user-crate.rs
new file mode 100644
index 00000000000..fc0d82727b5
--- /dev/null
+++ b/src/test/ui/rfc-2632-const-trait-impl/staged-api-user-crate.rs
@@ -0,0 +1,16 @@
+// aux-build: staged-api.rs
+extern crate staged_api;
+
+use staged_api::*;
+
+// Const stability has no impact on usage in non-const contexts.
+fn non_const_context() {
+    Unstable::func();
+}
+
+const fn stable_const_context() {
+    Unstable::func();
+    //~^ ERROR cannot call non-const fn `<staged_api::Unstable as staged_api::MyTrait>::func` in constant functions
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/staged-api-user-crate.stderr b/src/test/ui/rfc-2632-const-trait-impl/staged-api-user-crate.stderr
new file mode 100644
index 00000000000..61f9840e0d0
--- /dev/null
+++ b/src/test/ui/rfc-2632-const-trait-impl/staged-api-user-crate.stderr
@@ -0,0 +1,11 @@
+error[E0015]: cannot call non-const fn `<staged_api::Unstable as staged_api::MyTrait>::func` in constant functions
+  --> $DIR/staged-api-user-crate.rs:12:5
+   |
+LL |     Unstable::func();
+   |     ^^^^^^^^^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/src/test/ui/rfc-2632-const-trait-impl/staged-api.rs b/src/test/ui/rfc-2632-const-trait-impl/staged-api.rs
index 39a1b6066de..1d79f5adf93 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/staged-api.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/staged-api.rs
@@ -1,9 +1,7 @@
-// revisions: stock staged
-#![cfg_attr(staged, feature(staged))]
+// revisions: stable unstable
 
+#![cfg_attr(unstable, feature(unstable))] // The feature from the ./auxiliary/staged-api.rs file.
 #![feature(const_trait_impl)]
-#![allow(incomplete_features)]
-
 #![feature(staged_api)]
 #![stable(feature = "rust1", since = "1.0.0")]
 
@@ -13,27 +11,53 @@ extern crate staged_api;
 use staged_api::*;
 
 #[stable(feature = "rust1", since = "1.0.0")]
-pub struct Stable;
+pub struct Foo;
 
 #[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(staged, rustc_const_stable(feature = "rust1", since = "1.0.0"))]
-// ^ should trigger error with or without the attribute
-impl const MyTrait for Stable {
-    fn func() { //~ ERROR trait methods cannot be stable const fn
-
-    }
+#[cfg_attr(unstable, rustc_const_unstable(feature = "foo", issue = "none"))]
+#[cfg_attr(stable, rustc_const_stable(feature = "foo", since = "1.0.0"))]
+impl const MyTrait for Foo {
+    //[stable]~^ ERROR trait implementations cannot be const stable yet
+    fn func() {}
 }
 
+// Const stability has no impact on usage in non-const contexts.
 fn non_const_context() {
     Unstable::func();
-    Stable::func();
+    Foo::func();
 }
 
 #[unstable(feature = "none", issue = "none")]
 const fn const_context() {
     Unstable::func();
-    //[stock]~^ ERROR `<staged_api::Unstable as staged_api::MyTrait>::func` is not yet stable as a const fn
-    Stable::func();
+    // ^ This is okay regardless of whether the `unstable` feature is enabled, as this function is
+    // not const-stable.
+    Foo::func();
+    //[unstable]~^ ERROR not yet stable as a const fn
+    // ^ fails, because the `foo` feature is not active
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(unstable, rustc_const_unstable(feature = "foo", issue = "none"))]
+pub const fn const_context_not_const_stable() {
+    //[stable]~^ ERROR function has missing const stability attribute
+    Unstable::func();
+    // ^ This is okay regardless of whether the `unstable` feature is enabled, as this function is
+    // not const-stable.
+    Foo::func();
+    //[unstable]~^ ERROR not yet stable as a const fn
+    // ^ fails, because the `foo` feature is not active
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_stable(feature = "cheese", since = "1.0.0")]
+const fn stable_const_context() {
+    Unstable::func();
+    //[unstable]~^ ERROR not yet stable as a const fn
+    Foo::func();
+    //[unstable]~^ ERROR not yet stable as a const fn
+    const_context_not_const_stable()
+    //[unstable]~^ ERROR not yet stable as a const fn
 }
 
 fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/staged-api.stable.stderr b/src/test/ui/rfc-2632-const-trait-impl/staged-api.stable.stderr
new file mode 100644
index 00000000000..a1aca762ef4
--- /dev/null
+++ b/src/test/ui/rfc-2632-const-trait-impl/staged-api.stable.stderr
@@ -0,0 +1,25 @@
+error: trait implementations cannot be const stable yet
+  --> $DIR/staged-api.rs:19:1
+   |
+LL | / impl const MyTrait for Foo {
+LL | |
+LL | |     fn func() {}
+LL | | }
+   | |_^
+   |
+   = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
+
+error: function has missing const stability attribute
+  --> $DIR/staged-api.rs:42:1
+   |
+LL | / pub const fn const_context_not_const_stable() {
+LL | |
+LL | |     Unstable::func();
+LL | |     // ^ This is okay regardless of whether the `unstable` feature is enabled, as this function is
+...  |
+LL | |     // ^ fails, because the `foo` feature is not active
+LL | | }
+   | |_^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/rfc-2632-const-trait-impl/staged-api.staged.stderr b/src/test/ui/rfc-2632-const-trait-impl/staged-api.staged.stderr
deleted file mode 100644
index d2ff4ce2001..00000000000
--- a/src/test/ui/rfc-2632-const-trait-impl/staged-api.staged.stderr
+++ /dev/null
@@ -1,10 +0,0 @@
-error: trait methods cannot be stable const fn
-  --> $DIR/staged-api.rs:22:5
-   |
-LL | /     fn func() {
-LL | |
-LL | |     }
-   | |_____^
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/rfc-2632-const-trait-impl/staged-api.stock.stderr b/src/test/ui/rfc-2632-const-trait-impl/staged-api.stock.stderr
deleted file mode 100644
index 91c5469bd90..00000000000
--- a/src/test/ui/rfc-2632-const-trait-impl/staged-api.stock.stderr
+++ /dev/null
@@ -1,18 +0,0 @@
-error: trait methods cannot be stable const fn
-  --> $DIR/staged-api.rs:22:5
-   |
-LL | /     fn func() {
-LL | |
-LL | |     }
-   | |_____^
-
-error: `<staged_api::Unstable as staged_api::MyTrait>::func` is not yet stable as a const fn
-  --> $DIR/staged-api.rs:34:5
-   |
-LL |     Unstable::func();
-   |     ^^^^^^^^^^^^^^^^
-   |
-   = help: add `#![feature(staged)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
-
diff --git a/src/test/ui/rfc-2632-const-trait-impl/staged-api.unstable.stderr b/src/test/ui/rfc-2632-const-trait-impl/staged-api.unstable.stderr
new file mode 100644
index 00000000000..c38d1a81ae7
--- /dev/null
+++ b/src/test/ui/rfc-2632-const-trait-impl/staged-api.unstable.stderr
@@ -0,0 +1,42 @@
+error: `<Foo as staged_api::MyTrait>::func` is not yet stable as a const fn
+  --> $DIR/staged-api.rs:35:5
+   |
+LL |     Foo::func();
+   |     ^^^^^^^^^^^
+   |
+   = help: add `#![feature(foo)]` to the crate attributes to enable
+
+error: `<Foo as staged_api::MyTrait>::func` is not yet stable as a const fn
+  --> $DIR/staged-api.rs:47:5
+   |
+LL |     Foo::func();
+   |     ^^^^^^^^^^^
+   |
+   = help: add `#![feature(foo)]` to the crate attributes to enable
+
+error: `<staged_api::Unstable as staged_api::MyTrait>::func` is not yet stable as a const fn
+  --> $DIR/staged-api.rs:55:5
+   |
+LL |     Unstable::func();
+   |     ^^^^^^^^^^^^^^^^
+   |
+   = help: const-stable functions can only call other const-stable functions
+
+error: `<Foo as staged_api::MyTrait>::func` is not yet stable as a const fn
+  --> $DIR/staged-api.rs:57:5
+   |
+LL |     Foo::func();
+   |     ^^^^^^^^^^^
+   |
+   = help: const-stable functions can only call other const-stable functions
+
+error: `const_context_not_const_stable` is not yet stable as a const fn
+  --> $DIR/staged-api.rs:59:5
+   |
+LL |     const_context_not_const_stable()
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: const-stable functions can only call other const-stable functions
+
+error: aborting due to 5 previous errors
+
diff --git a/src/test/ui/stability-attribute/missing-const-stability.rs b/src/test/ui/stability-attribute/missing-const-stability.rs
index 57e64737d0f..d89886af314 100644
--- a/src/test/ui/stability-attribute/missing-const-stability.rs
+++ b/src/test/ui/stability-attribute/missing-const-stability.rs
@@ -18,9 +18,15 @@ impl Foo {
     pub const fn bar() {} // ok because function is unstable
 }
 
-// FIXME Once #![feature(const_trait_impl)] is allowed to be stable, add a test
-// for const trait impls. Right now, a "trait methods cannot be stable const fn"
-// error is emitted. This occurs prior to the lint being tested here, such that
-// the lint cannot currently be tested on this use case.
+#[stable(feature = "stable", since = "1.0.0")]
+pub trait Bar {
+    #[stable(feature = "stable", since = "1.0.0")]
+    fn fun();
+}
+#[stable(feature = "stable", since = "1.0.0")]
+impl const Bar for Foo {
+    //~^ ERROR implementation has missing const stability attribute
+    fn fun() {}
+}
 
 fn main() {}
diff --git a/src/test/ui/stability-attribute/missing-const-stability.stderr b/src/test/ui/stability-attribute/missing-const-stability.stderr
index 7eba99a477a..6f2ade0d0ab 100644
--- a/src/test/ui/stability-attribute/missing-const-stability.stderr
+++ b/src/test/ui/stability-attribute/missing-const-stability.stderr
@@ -10,5 +10,14 @@ error: associated function has missing const stability attribute
 LL |     pub const fn foo() {}
    |     ^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 2 previous errors
+error: implementation has missing const stability attribute
+  --> $DIR/missing-const-stability.rs:27:1
+   |
+LL | / impl const Bar for Foo {
+LL | |
+LL | |     fn fun() {}
+LL | | }
+   | |_^
+
+error: aborting due to 3 previous errors