Skip to content

WIP: Unstable impls #140399

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 21 commits into
base: master
Choose a base branch
from
Draft

WIP: Unstable impls #140399

wants to merge 21 commits into from

Conversation

tiif
Copy link
Member

@tiif tiif commented Apr 28, 2025

r? ghost

@rustbot rustbot added A-attributes Area: Attributes (`#[…]`, `#![…]`) S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-rustdoc Relevant to the rustdoc team, which will review and decide on the PR/issue. WG-trait-system-refactor The Rustc Trait System Refactor Initiative (-Znext-solver) labels Apr 28, 2025
@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@BoxyUwU BoxyUwU self-assigned this May 27, 2025
@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@bors
Copy link
Collaborator

bors commented Jun 10, 2025

☔ The latest upstream changes (presumably #142299) made this pull request unmergeable. Please resolve the merge conflicts.

Copy link
Member Author

@tiif tiif Jun 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we stop making TypingMode::PostAnalysis return Ok(Yes) when proving ClauseKind::UnstableFeature, this test will ice: #142368 (comment)

This means the test is working as intended,

@jhpratt
Copy link
Member

jhpratt commented Jun 11, 2025

I've got nothing technical to add (I've not looked over the code). I just wanted to thank @tiif for taking on this task! It's far from trivial and has been a long-standing desire.

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@bors
Copy link
Collaborator

bors commented Jun 14, 2025

☔ The latest upstream changes (presumably #142483) made this pull request unmergeable. Please resolve the merge conflicts.

Copy link
Member

@BoxyUwU BoxyUwU left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gg gamer

continue;

match pred.kind().skip_binder() {
ty::ClauseKind::WellFormed(..) | ty::ClauseKind::UnstableFeature(..) => continue,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
ty::ClauseKind::WellFormed(..) | ty::ClauseKind::UnstableFeature(..) => continue,
ty::ClauseKind::WellFormed(..)
// Unstable feature goals cannot be proven in an empty environment so skip them
| ty::ClauseKind::UnstableFeature(..) => continue,

and then can u move the comment about WellFormed onto the WellFormed pattern instead of the whole match

@@ -157,7 +157,8 @@ pub enum AttributeKind {

/// Represents `#[allow_internal_unstable]`.
AllowInternalUnstable(ThinVec<(Symbol, Span)>),

/// Represents `#[unstable_feature_bound]`.
AllowUnstableFeature(ThinVec<(Symbol, Span)>),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
AllowUnstableFeature(ThinVec<(Symbol, Span)>),
UnstableFeatureBound(ThinVec<(Symbol, Span)>),

@@ -24,6 +24,22 @@ impl<S: Stage> CombineAttributeParser<S> for AllowInternalUnstableParser {
}
}

pub(crate) struct AllowUnstableFeatureParser;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
pub(crate) struct AllowUnstableFeatureParser;
pub(crate) struct UnstableFeatureBoundParser;

@@ -318,6 +319,16 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
predicates.extend(const_evaluatable_predicates_of(tcx, def_id, &predicates));
}

let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id));
let allow_unstable_feature_attr =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let allow_unstable_feature_attr =
// FIXME(staged_api): We might want to look at the normal stability attributes too but
// first we would need a way to let std/core use APIs with unstable feature bounds from
// within stable APIs.
let allow_unstable_feature_attr =

Comment on lines +805 to +808
let unstable_feature_stab =
find_attr!(attrs, AttributeKind::AllowUnstableFeature(i) => i)
.map(|i| i.as_slice())
.unwrap_or_default();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this won't work if there are multiple unstable_feature_bound attributes. E.g.

#[unstable_feature_bound(feat_foo)]
#[unstable_feature_bound(feat_bar)]
#[unstable(feature = "feat_bar", issue = "none")]
impl Foo for Bar {}

you should be able to do something like:
find_attr!(attrs, AttributeKind::AllowUnstableFeature(i) if i == feature)
to get a yes/no as to whether there's an unstable feature bound on the impl with the same symbol as the stability attr

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This reminds me, I am not sure if I handled multiple attributes case correctly in compiler/rustc_hir_analysis/src/collect/predicates_of.rs. I will take a look at that too.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh, yes, I don't think that's correct either

// For example:
// ```
// #[unstable_feature_bound(feat_foo)]
// #![unstable(feature = "feat_foo", issue = "none")]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// #![unstable(feature = "feat_foo", issue = "none")]
// #[unstable(feature = "feat_foo", issue = "none")]

@@ -410,6 +409,8 @@ impl<I: Interner> FlagComputation<I> {
self.add_term(t1);
self.add_term(t2);
}
ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_))
ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_sym))

to make it a little clearer to readers what the field is that we're ignoring here

Comment on lines +216 to +217
/// Allow declaring an impl as unstable.
(internal, impl_stability, "CURRENT_RUSTC_VERSION", None),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Allow declaring an impl as unstable.
(internal, impl_stability, "CURRENT_RUSTC_VERSION", None),

I think that unstable feature bounds should just live under the staged_api feature instead of a separate feature gate. Might be a somewhat involved change to go and change everywhere to use staged_api instead of impl_stability everywhere :> my bad

Comment on lines +165 to +182
if self.cx().features().impl_stability() {
// If we are in std/core, and the feature is not enabled through #[unstable_feature_bound(..)]
return self.evaluate_added_goals_and_make_canonical_response(Certainty::Maybe(
MaybeCause::Ambiguity,
));
} else {
// Outside of std/core, check if feature is enabled at crate level with #[feature(..)]
// or if we are currently in codegen.
if self.cx().features().enabled(symbol)
|| (self.typing_mode() == TypingMode::PostAnalysis)
{
return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
} else {
return self.evaluate_added_goals_and_make_canonical_response(Certainty::Maybe(
MaybeCause::Ambiguity,
));
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if self.cx().features().impl_stability() {
// If we are in std/core, and the feature is not enabled through #[unstable_feature_bound(..)]
return self.evaluate_added_goals_and_make_canonical_response(Certainty::Maybe(
MaybeCause::Ambiguity,
));
} else {
// Outside of std/core, check if feature is enabled at crate level with #[feature(..)]
// or if we are currently in codegen.
if self.cx().features().enabled(symbol)
|| (self.typing_mode() == TypingMode::PostAnalysis)
{
return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
} else {
return self.evaluate_added_goals_and_make_canonical_response(Certainty::Maybe(
MaybeCause::Ambiguity,
));
}
}
// During codegen we must assume that all feature bounds hold as we may be
// monomorphizing a body from an upstream crate which had an unstable feature
// enabled that we do not.
//
// Note: `feature_bound_holds_in_crate` does not consider a feature to be enabled
// if we are in std/core even if there is a corresponding `feature` attribute on the crate.
if self.cx().features().feature_bound_holds_in_crate(symbol)
|| (self.typing_mode() == TypingMode::PostAnalysis)
{
return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
} else {
return self.evaluate_added_goals_and_make_canonical_response(Certainty::Maybe(
MaybeCause::Ambiguity,
));
}

Minor structural change here. Moving the "are we in std/core" check to within the feature_bound_holds_in_crate method. I think it makes the code a little nicer and also makes the enabled feature only suitable for use by unstable feature bounds which will prevent people using the API elsewhere.

Comment on lines +840 to +842
fn enabled(self, symbol: <TyCtxt<'tcx> as Interner>::Symbol) -> bool {
self.enabled(symbol)
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
fn enabled(self, symbol: <TyCtxt<'tcx> as Interner>::Symbol) -> bool {
self.enabled(symbol)
}
fn feature_bound_holds_in_crate(self, symbol: <TyCtxt<'tcx> as Interner>::Symbol) -> bool {
// We don't consider feature bounds to hold in the crate if we `staged_api` feature is
// even when the feature is enabled. This is to prevent accidentally leaking unstable APIs
// to stable.
!self.staged_api() && self.enabled(symbol)
}

@@ -2274,6 +2277,45 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
}
}

fn check_unstable_feature_bound(&self, attr_span: Span, span: Span, target: Target) {
match target {
Target::Fn | Target::Impl => {}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Target::Fn | Target::Impl => {}
// FIXME(staged_api): There's no reason we can't support more targets here. We're just
// being conservative to begin with.
Target::Fn | Target::Impl => {}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-attributes Area: Attributes (`#[…]`, `#![…]`) S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-rustdoc Relevant to the rustdoc team, which will review and decide on the PR/issue. WG-trait-system-refactor The Rustc Trait System Refactor Initiative (-Znext-solver)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants