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`
This commit is contained in:
bors
2025-07-17 01:57:55 +00:00
82 changed files with 1064 additions and 13 deletions

View File

@@ -27,6 +27,26 @@ impl<S: Stage> CombineAttributeParser<S> for AllowInternalUnstableParser {
}
}
pub(crate) struct UnstableFeatureBoundParser;
impl<S: Stage> CombineAttributeParser<S> for UnstableFeatureBoundParser {
const PATH: &'static [rustc_span::Symbol] = &[sym::unstable_feature_bound];
type Item = (Symbol, Span);
const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::UnstableFeatureBound(items);
const TEMPLATE: AttributeTemplate = template!(Word, List: "feat1, feat2, ...");
fn extend<'c>(
cx: &'c mut AcceptContext<'_, '_, S>,
args: &'c ArgParser<'_>,
) -> impl IntoIterator<Item = Self::Item> {
if !cx.features().staged_api() {
cx.emit_err(session_diagnostics::StabilityOutsideStd { span: cx.attr_span });
}
parse_unstable(cx, args, <Self as CombineAttributeParser<S>>::PATH[0])
.into_iter()
.zip(iter::repeat(cx.attr_span))
}
}
pub(crate) struct AllowConstFnUnstableParser;
impl<S: Stage> CombineAttributeParser<S> for AllowConstFnUnstableParser {
const PATH: &[Symbol] = &[sym::rustc_allow_const_fn_unstable];

View File

@@ -98,6 +98,16 @@ impl<S: Stage> AttributeParser<S> for StabilityParser {
}
}
if let Some((Stability { level: StabilityLevel::Stable { .. }, .. }, _)) = self.stability {
for other_attr in cx.all_attrs {
if other_attr.word_is(sym::unstable_feature_bound) {
cx.emit_err(session_diagnostics::UnstableFeatureBoundIncompatibleStability {
span: cx.target_span,
});
}
}
}
let (stability, span) = self.stability?;
Some(AttributeKind::Stability { stability, span })

View File

@@ -13,7 +13,9 @@ use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, HirI
use rustc_session::Session;
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser};
use crate::attributes::allow_unstable::{
AllowConstFnUnstableParser, AllowInternalUnstableParser, UnstableFeatureBoundParser,
};
use crate::attributes::codegen_attrs::{
ColdParser, ExportNameParser, NakedParser, NoMangleParser, OmitGdbPrettyPrinterSectionParser,
OptimizeParser, TargetFeatureParser, TrackCallerParser, UsedParser,
@@ -133,6 +135,7 @@ attribute_parsers!(
Combine<AllowInternalUnstableParser>,
Combine<ReprParser>,
Combine<TargetFeatureParser>,
Combine<UnstableFeatureBoundParser>,
// tidy-alphabetical-end
// tidy-alphabetical-start

View File

@@ -503,6 +503,14 @@ pub(crate) struct UnrecognizedReprHint {
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_unstable_feature_bound_incompatible_stability)]
#[help]
pub(crate) struct UnstableFeatureBoundIncompatibleStability {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_naked_functions_incompatible_attribute, code = E0736)]
pub(crate) struct NakedFunctionIncompatibleAttribute {