Skip to content

Commit 50d7616

Browse files
committed
Skip the lint if there is unstable_feature_bound
1 parent 3672c13 commit 50d7616

File tree

2 files changed

+52
-2
lines changed

2 files changed

+52
-2
lines changed

compiler/rustc_passes/src/stability.rs

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -801,22 +801,47 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
801801
// FIXME(jdonszelmann): make it impossible to miss the or_else in the typesystem
802802
let const_stab = attrs::find_attr!(attrs, AttributeKind::ConstStability{stability, ..} => *stability);
803803

804+
let unstable_feature_stab =
805+
find_attr!(attrs, AttributeKind::AllowUnstableFeature(i) => i)
806+
.map(|i| i.as_slice())
807+
.unwrap_or_default();
808+
804809
// If this impl block has an #[unstable] attribute, give an
805810
// error if all involved types and traits are stable, because
806811
// it will have no effect.
807812
// See: https://github.com/rust-lang/rust/issues/55436
813+
//
814+
// The exception is when there is both #[unstable_feature_bound(..)] and
815+
// #![unstable(feature = "..", issue = "..")] that have the same symbol because
816+
// that can effectively mark an impl as unstable.
817+
//
818+
// For example:
819+
// ```
820+
// #[unstable_feature_bound(feat_foo)]
821+
// #![unstable(feature = "feat_foo", issue = "none")]
822+
// impl Foo for Bar {}
823+
// ```
808824
if let Some((
809-
Stability { level: attrs::StabilityLevel::Unstable { .. }, .. },
825+
Stability { level: attrs::StabilityLevel::Unstable { ..}, feature},
810826
span,
811827
)) = stab
812828
{
813829
let mut c = CheckTraitImplStable { tcx: self.tcx, fully_stable: true };
814830
c.visit_ty_unambig(self_ty);
815831
c.visit_trait_ref(t);
816832

833+
// Skip the lint if the impl is marked as unstable using
834+
// #[unstable_feature_bound(..)]
835+
let mut unstable_feature_bound_in_effect = false;
836+
for (unstable_bound_feat_name, _) in unstable_feature_stab {
837+
if *unstable_bound_feat_name == feature {
838+
unstable_feature_bound_in_effect = true;
839+
}
840+
}
841+
817842
// do not lint when the trait isn't resolved, since resolution error should
818843
// be fixed first
819-
if t.path.res != Res::Err && c.fully_stable {
844+
if t.path.res != Res::Err && c.fully_stable && !unstable_feature_bound_in_effect {
820845
self.tcx.emit_node_span_lint(
821846
INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
822847
item.hir_id(),
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#![allow(internal_features)] // Enabled to use #![feature(staged_api)] and #![feature(impl_stability)]
2+
//~^ ERROR: module has missing stability attribute
3+
#![feature(staged_api)] // Enabled to use #![unstable(feature = "feat_foo", issue = "none")]
4+
#![feature(impl_stability)] // Enabled to use #[unstable_feature_bound(feat_foo)]
5+
#![allow(dead_code)]
6+
7+
#[stable(feature = "a", since = "1.1.1" )]
8+
trait Moo {}
9+
#[stable(feature = "a", since = "1.1.1" )]
10+
trait Foo {}
11+
#[stable(feature = "a", since = "1.1.1" )]
12+
pub struct Bar;
13+
14+
15+
// If #[unstable_feature_bound] and #[unstable] has different name,
16+
// It should throw an error.
17+
#[unstable(feature = "feat_moo", issue = "none" )]
18+
#[unstable_feature_bound(feat_foo)] //~^ ERROR: an `#[unstable]` annotation here has no effect
19+
impl Moo for Bar {}
20+
21+
#[unstable(feature = "feat_foo", issue = "none" )]
22+
#[unstable_feature_bound(feat_foo)]
23+
impl Foo for Bar {}
24+
25+
fn main() {}

0 commit comments

Comments
 (0)