about summary refs log tree commit diff
path: root/compiler/rustc_middle/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2025-07-17 01:57:55 +0000
committerbors <bors@rust-lang.org>2025-07-17 01:57:55 +0000
commit014bd8290f084c714995205a9116e6c035419ae6 (patch)
tree70a98d65e3a93b13c6c896c708c4b66c373733c1 /compiler/rustc_middle/src
parentfd2eb391d032181459773f3498c17b198513e0d0 (diff)
parente331de149f4fe5ddafe7f4bad13acb1499a6108e (diff)
downloadrust-014bd8290f084c714995205a9116e6c035419ae6.tar.gz
rust-014bd8290f084c714995205a9116e6c035419ae6.zip
Auto merge of #140399 - tiif:unstable_impl, r=lcnr,BoxyUwU
Implement unstable trait impl

This PR allows marking impls of stable trait with stable type as unstable.

## Approach

In std/core, an impl can be marked as unstable by annotating it with ``#[unstable_feature_bound(feat_name)]``. This will add a ``ClauseKind::Unstable_Feature(feat_name)`` to the list of predicates in ``predicates_of`` .

When an unstable impl's function is called, we will first iterate through all the goals in ``param_env`` to check if there is any ``ClauseKind::UnstableFeature(feat_name)`` in ``param_env``.

The existence of ``ClauseKind::Unstable_Feature(feat_name)`` in ``param_env`` means an``#[unstable_feature_bound(feat_name)]`` is present at the call site of the function, so we allow the check to succeed in this case.

If ``ClauseKind::UnstableFeature(feat_name)`` does not exist in ``param_env``, we will still allow the check to succeed for either of the cases below:
1. The feature is enabled through ``#[feature(feat_name)]`` outside of std / core.
2. We are in codegen because we may be monomorphizing a body from an upstream crate which had an unstable feature enabled that the downstream crate do not.

For the rest of the case, it will fail with ambiguity.

## Limitation

In this PR, we do not support:
1. using items that need ``#[unstable_feature_bound]`` within stable APIs
2. annotate main function with ``#[unstable_feature_bound]``
3. annotate ``#[unstable_feature_bound]`` on items other than free function and impl

## Acknowledgement
The design and mentoring are done by `@BoxyUwU`
Diffstat (limited to 'compiler/rustc_middle/src')
-rw-r--r--compiler/rustc_middle/src/ty/context.rs8
-rw-r--r--compiler/rustc_middle/src/ty/predicate.rs3
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs1
3 files changed, 12 insertions, 0 deletions
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 98b2ce01d89..915b062417f 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -137,6 +137,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
     type FnInputTys = &'tcx [Ty<'tcx>];
     type ParamTy = ParamTy;
     type BoundTy = ty::BoundTy;
+    type Symbol = Symbol;
 
     type PlaceholderTy = ty::PlaceholderType;
     type ErrorGuaranteed = ErrorGuaranteed;
@@ -833,6 +834,13 @@ impl<'tcx> rustc_type_ir::inherent::Features<TyCtxt<'tcx>> for &'tcx rustc_featu
     fn associated_const_equality(self) -> bool {
         self.associated_const_equality()
     }
+
+    fn feature_bound_holds_in_crate(self, symbol: Symbol) -> bool {
+        // We don't consider feature bounds to hold in the crate when `staged_api` feature is
+        // enabled, even if it is enabled through `#[feature]`.
+        // This is to prevent accidentally leaking unstable APIs to stable.
+        !self.staged_api() && self.enabled(symbol)
+    }
 }
 
 impl<'tcx> rustc_type_ir::inherent::Span<TyCtxt<'tcx>> for Span {
diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs
index bc2ac42b6b1..ec2224877a8 100644
--- a/compiler/rustc_middle/src/ty/predicate.rs
+++ b/compiler/rustc_middle/src/ty/predicate.rs
@@ -131,6 +131,7 @@ impl<'tcx> Predicate<'tcx> {
             | PredicateKind::Clause(ClauseKind::TypeOutlives(_))
             | PredicateKind::Clause(ClauseKind::Projection(_))
             | PredicateKind::Clause(ClauseKind::ConstArgHasType(..))
+            | PredicateKind::Clause(ClauseKind::UnstableFeature(_))
             | PredicateKind::DynCompatible(_)
             | PredicateKind::Subtype(_)
             | PredicateKind::Coerce(_)
@@ -649,6 +650,7 @@ impl<'tcx> Predicate<'tcx> {
             PredicateKind::Clause(ClauseKind::Projection(..))
             | PredicateKind::Clause(ClauseKind::HostEffect(..))
             | PredicateKind::Clause(ClauseKind::ConstArgHasType(..))
+            | PredicateKind::Clause(ClauseKind::UnstableFeature(_))
             | PredicateKind::NormalizesTo(..)
             | PredicateKind::AliasRelate(..)
             | PredicateKind::Subtype(..)
@@ -670,6 +672,7 @@ impl<'tcx> Predicate<'tcx> {
             PredicateKind::Clause(ClauseKind::Trait(..))
             | PredicateKind::Clause(ClauseKind::HostEffect(..))
             | PredicateKind::Clause(ClauseKind::ConstArgHasType(..))
+            | PredicateKind::Clause(ClauseKind::UnstableFeature(_))
             | PredicateKind::NormalizesTo(..)
             | PredicateKind::AliasRelate(..)
             | PredicateKind::Subtype(..)
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 8f0f9b21dc1..1ff90bf0e4c 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -3237,6 +3237,7 @@ define_print! {
             ty::ClauseKind::ConstEvaluatable(ct) => {
                 p!("the constant `", print(ct), "` can be evaluated")
             }
+            ty::ClauseKind::UnstableFeature(symbol) => p!("unstable feature: ", write("`{}`", symbol)),
         }
     }