Skip to content

Try: stop special casing codegen for unstable impl #142368

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

Closed
wants to merge 17 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion compiler/rustc_attr_data_structures/src/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,8 @@ pub enum AttributeKind {

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

/// Represents `#[unstable_feature_bound]`.
AllowUnstableFeature(ThinVec<(Symbol, Span)>),
/// Represents `#[rustc_default_body_unstable]`.
BodyStability {
stability: DefaultBodyStability,
Expand Down
14 changes: 14 additions & 0 deletions compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,20 @@ impl CombineAttributeParser for AllowInternalUnstableParser {
}
}

pub(crate) struct AllowUnstableFeatureParser;
impl CombineAttributeParser for AllowUnstableFeatureParser {
const PATH: &'static [rustc_span::Symbol] = &[sym::unstable_feature_bound];
type Item = (Symbol, Span);
const CONVERT: ConvertFn<Self::Item> = AttributeKind::AllowUnstableFeature;

fn extend<'a>(
cx: &'a AcceptContext<'a>,
args: &'a ArgParser<'a>,
) -> impl IntoIterator<Item = Self::Item> + 'a {
parse_unstable(cx, args, Self::PATH[0]).into_iter().zip(iter::repeat(cx.attr_span))
}
}

pub(crate) struct AllowConstFnUnstableParser;
impl CombineAttributeParser for AllowConstFnUnstableParser {
const PATH: &'static [Symbol] = &[sym::rustc_allow_const_fn_unstable];
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_attr_parsing/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId};
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, AllowUnstableFeatureParser,
};
use crate::attributes::confusables::ConfusablesParser;
use crate::attributes::deprecation::DeprecationParser;
use crate::attributes::repr::ReprParser;
Expand Down Expand Up @@ -75,6 +77,7 @@ attribute_groups!(
// tidy-alphabetical-start
Combine<AllowConstFnUnstableParser>,
Combine<AllowInternalUnstableParser>,
Combine<AllowUnstableFeatureParser>,
Combine<ReprParser>,
// tidy-alphabetical-end

Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_feature/src/builtin_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -655,6 +655,11 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
DuplicatesOk, EncodeCrossCrate::Yes,
"allow_internal_unstable side-steps feature gating and stability checks",
),
gated!(
unstable_feature_bound, Normal, template!(Word, List: "feat1, feat2, ..."),
DuplicatesOk, EncodeCrossCrate::No, impl_stability,
"used internally to mark impl as unstable",
),
gated!(
allow_internal_unsafe, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::No, "allow_internal_unsafe side-steps the unsafe_code lint",
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_feature/src/unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,8 @@ declare_features! (
(internal, custom_mir, "1.65.0", None),
/// Outputs useful `assert!` messages
(unstable, generic_assert, "1.63.0", None),
/// Allow declaring an impl as unstable.
(internal, impl_stability, "CURRENT_RUSTC_VERSION", None),
/// Allows using the #[rustc_intrinsic] attribute.
(internal, intrinsics, "1.0.0", None),
/// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic.
Expand Down
7 changes: 5 additions & 2 deletions compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2368,9 +2368,12 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
// We lower empty bounds like `Vec<dyn Copy>:` as
// `WellFormed(Vec<dyn Copy>)`, which will later get checked by
// regular WF checking
if let ty::ClauseKind::WellFormed(..) = pred.kind().skip_binder() {
continue;

match pred.kind().skip_binder() {
ty::ClauseKind::WellFormed(..) | ty::ClauseKind::UnstableFeature(..) => continue,
_ => {}
}

// Match the existing behavior.
if pred.is_global() && !pred.has_type_flags(TypeFlags::HAS_BINDER_VARS) {
let pred = self.normalize(span, None, pred);
Expand Down
13 changes: 13 additions & 0 deletions compiler/rustc_hir_analysis/src/collect/predicates_of.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::assert_matches::assert_matches;

use hir::Node;
use rustc_attr_data_structures::{AttributeKind, find_attr};
use rustc_data_structures::fx::FxIndexSet;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
Expand Down Expand Up @@ -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 =
find_attr!(attrs, AttributeKind::AllowUnstableFeature(i) => i)
.map(|i| i.as_slice())
.unwrap_or_default();

for (feat_name, span) in allow_unstable_feature_attr {
predicates.insert((ty::ClauseKind::UnstableFeature(*feat_name).upcast(tcx), *span));
}

let mut predicates: Vec<_> = predicates.into_iter().collect();

// Subtle: before we store the predicates into the tcx, we
Expand Down Expand Up @@ -747,6 +758,7 @@ pub(super) fn assert_only_contains_predicates_from<'tcx>(
ty::ClauseKind::RegionOutlives(_)
| ty::ClauseKind::ConstArgHasType(_, _)
| ty::ClauseKind::WellFormed(_)
| ty::ClauseKind::UnstableFeature(_)
| ty::ClauseKind::ConstEvaluatable(_) => {
bug!(
"unexpected non-`Self` predicate when computing \
Expand Down Expand Up @@ -774,6 +786,7 @@ pub(super) fn assert_only_contains_predicates_from<'tcx>(
| ty::ClauseKind::ConstArgHasType(_, _)
| ty::ClauseKind::WellFormed(_)
| ty::ClauseKind::ConstEvaluatable(_)
| ty::ClauseKind::UnstableFeature(_)
| ty::ClauseKind::HostEffect(..) => {
bug!(
"unexpected non-`Self` predicate when computing \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,7 @@ fn trait_specialization_kind<'tcx>(
| ty::ClauseKind::ConstArgHasType(..)
| ty::ClauseKind::WellFormed(_)
| ty::ClauseKind::ConstEvaluatable(..)
| ty::ClauseKind::UnstableFeature(_)
| ty::ClauseKind::HostEffect(..) => None,
}
}
1 change: 1 addition & 0 deletions compiler/rustc_hir_analysis/src/outlives/explicit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> {
| ty::ClauseKind::ConstArgHasType(_, _)
| ty::ClauseKind::WellFormed(_)
| ty::ClauseKind::ConstEvaluatable(_)
| ty::ClauseKind::UnstableFeature(_)
| ty::ClauseKind::HostEffect(..) => {}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
| ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
| ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..))
| ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_))
| ty::PredicateKind::Ambiguous => false,
}
}
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir_typeck/src/method/probe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -926,6 +926,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
| ty::ClauseKind::ConstArgHasType(_, _)
| ty::ClauseKind::WellFormed(_)
| ty::ClauseKind::ConstEvaluatable(_)
| ty::ClauseKind::UnstableFeature(_)
| ty::ClauseKind::HostEffect(..) => None,
}
});
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_lint/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1569,8 +1569,9 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
ClauseKind::TypeOutlives(..) |
ClauseKind::RegionOutlives(..) => "lifetime",

ClauseKind::UnstableFeature(_)
// `ConstArgHasType` is never global as `ct` is always a param
ClauseKind::ConstArgHasType(..)
| ClauseKind::ConstArgHasType(..)
// Ignore projections, as they can only be global
// if the trait bound is global
| ClauseKind::Projection(..)
Expand Down
9 changes: 9 additions & 0 deletions compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,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;
Expand Down Expand Up @@ -827,6 +828,14 @@ impl<'tcx> rustc_type_ir::inherent::Features<TyCtxt<'tcx>> for &'tcx rustc_featu
fn associated_const_equality(self) -> bool {
self.associated_const_equality()
}

fn impl_stability(self) -> bool {
self.impl_stability()
}

fn enabled(self, symbol: <TyCtxt<'tcx> as Interner>::Symbol) -> bool {
self.enabled(symbol)
}
}

impl<'tcx> rustc_type_ir::inherent::Span<TyCtxt<'tcx>> for Span {
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_middle/src/ty/predicate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(_)
Expand Down Expand Up @@ -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(..)
Expand All @@ -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(..)
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_middle/src/ty/print/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3250,6 +3250,7 @@ define_print! {
ty::ClauseKind::ConstEvaluatable(ct) => {
p!("the constant `", print(ct), "` can be evaluated")
}
ty::ClauseKind::UnstableFeature(symbol) => p!("unstable feature: ", write("`{}`", symbol)),
}
}

Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,9 @@ where
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
self.compute_const_arg_has_type_goal(Goal { param_env, predicate: (ct, ty) })
}
ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(symbol)) => {
self.compute_unstable_feature_goal(param_env, symbol)
}
ty::PredicateKind::Subtype(predicate) => {
self.compute_subtype_goal(Goal { param_env, predicate })
}
Expand Down
32 changes: 32 additions & 0 deletions compiler/rustc_next_trait_solver/src/solve/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,38 @@ where
}
}

fn compute_unstable_feature_goal(
&mut self,
param_env: <I as Interner>::ParamEnv,
symbol: <I as Interner>::Symbol,
) -> QueryResult<I> {
// Iterate through all goals in param_env to find the one that has the same symbol.
for pred in param_env.caller_bounds().iter() {
if let ty::ClauseKind::UnstableFeature(sym) = pred.kind().skip_binder() {
if sym == symbol {
return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
}
}
}

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) {
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,
));
}
}
}

#[instrument(level = "trace", skip(self))]
fn compute_const_evaluatable_goal(
&mut self,
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
}
Attribute::Parsed(AttributeKind::Repr(_)) => { /* handled below this loop and elsewhere */
}
Attribute::Parsed(AttributeKind::AllowUnstableFeature(_)) => {
// FIXME: handle this later.
}
Attribute::Parsed(
AttributeKind::BodyStability { .. }
| AttributeKind::ConstStabilityIndirect
Expand Down
32 changes: 30 additions & 2 deletions compiler/rustc_passes/src/stability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -801,22 +801,50 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
// FIXME(jdonszelmann): make it impossible to miss the or_else in the typesystem
let const_stab = attrs::find_attr!(attrs, AttributeKind::ConstStability{stability, ..} => *stability);

let unstable_feature_stab =
find_attr!(attrs, AttributeKind::AllowUnstableFeature(i) => i)
.map(|i| i.as_slice())
.unwrap_or_default();

// 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
//
// The exception is when there are both #[unstable_feature_bound(..)] and
// #![unstable(feature = "..", issue = "..")] that have the same symbol because
// that can effectively mark an impl as unstable.
//
// For example:
// ```
// #[unstable_feature_bound(feat_foo)]
// #![unstable(feature = "feat_foo", issue = "none")]
// impl Foo for Bar {}
// ```
if let Some((
Stability { level: attrs::StabilityLevel::Unstable { .. }, .. },
Stability { level: attrs::StabilityLevel::Unstable { .. }, feature },
span,
)) = stab
{
let mut c = CheckTraitImplStable { tcx: self.tcx, fully_stable: true };
c.visit_ty_unambig(self_ty);
c.visit_trait_ref(t);

// Skip the lint if the impl is marked as unstable using
// #[unstable_feature_bound(..)]
let mut unstable_feature_bound_in_effect = false;
for (unstable_bound_feat_name, _) in unstable_feature_stab {
if *unstable_bound_feat_name == feature {
unstable_feature_bound_in_effect = true;
}
}

// do not lint when the trait isn't resolved, since resolution error should
// be fixed first
if t.path.res != Res::Err && c.fully_stable {
if t.path.res != Res::Err
&& c.fully_stable
&& !unstable_feature_bound_in_effect
{
self.tcx.emit_node_span_lint(
INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
item.hir_id(),
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_privacy/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ where
}
ty::ClauseKind::ConstEvaluatable(ct) => ct.visit_with(self),
ty::ClauseKind::WellFormed(term) => term.visit_with(self),
ty::ClauseKind::UnstableFeature(_) => V::Result::output(),
}
}

Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_smir/src/rustc_smir/convert/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,9 @@ impl<'tcx> Stable<'tcx> for ty::ClauseKind<'tcx> {
ClauseKind::HostEffect(..) => {
todo!()
}
ClauseKind::UnstableFeature(_) => {
todo!()
}
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1173,6 +1173,7 @@ symbols! {
ignore,
impl_header_lifetime_elision,
impl_lint_pass,
impl_stability,
impl_trait_in_assoc_type,
impl_trait_in_bindings,
impl_trait_in_fn_trait_return,
Expand Down Expand Up @@ -2265,6 +2266,7 @@ symbols! {
unsized_locals,
unsized_tuple_coercion,
unstable,
unstable_feature_bound,
unstable_location_reason_default: "this crate is being loaded from the sysroot, an \
unstable location; did you mean to load this crate \
from crates.io via `Cargo.toml` instead?",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
| ty::PredicateKind::ConstEquate { .. }
// Ambiguous predicates should never error
| ty::PredicateKind::Ambiguous
// We never return Err when proving UnstableFeature goal.
| ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature{ .. })
| ty::PredicateKind::NormalizesTo { .. }
| ty::PredicateKind::AliasRelate { .. }
| ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType { .. }) => {
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_trait_selection/src/traits/auto_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -800,6 +800,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
// FIXME(generic_const_exprs): you can absolutely add this as a where clauses
| ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
| ty::PredicateKind::Coerce(..)
| ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_))
| ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) => {}
ty::PredicateKind::Ambiguous => return false,
};
Expand Down
Loading
Loading