Skip to content

Commit 22c9505

Browse files
committed
Make stability attribute not to error if unstable_feature_bound is in effect
1 parent 6f5b1d2 commit 22c9505

File tree

3 files changed

+88
-2
lines changed

3 files changed

+88
-2
lines changed

compiler/rustc_passes/src/stability.rs

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -801,22 +801,50 @@ 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 are 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
845+
&& c.fully_stable
846+
&& !unstable_feature_bound_in_effect
847+
{
820848
self.tcx.emit_node_span_lint(
821849
INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
822850
item.hir_id(),
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#![allow(internal_features)]
2+
//~^ ERROR: module has missing stability attribute
3+
#![feature(staged_api)]
4+
#![feature(impl_stability)]
5+
#![allow(dead_code)]
6+
7+
/// If #[unstable(..)] and #[unstable_feature_name(..)] have the same feature name,
8+
/// the error should not be thrown as it can effectively mark an impl as unstable.
9+
///
10+
/// If the feature name in #[feature] does not exist in #[unstable_feature_bound(..)]
11+
/// an error should still be thrown because that feature will not be unstable.
12+
13+
#[stable(feature = "a", since = "1.1.1" )]
14+
trait Moo {}
15+
#[stable(feature = "a", since = "1.1.1" )]
16+
trait Foo {}
17+
#[stable(feature = "a", since = "1.1.1" )]
18+
trait Boo {}
19+
#[stable(feature = "a", since = "1.1.1" )]
20+
pub struct Bar;
21+
22+
23+
#[unstable(feature = "feat_moo", issue = "none" )]
24+
#[unstable_feature_bound(feat_foo)] //~^ ERROR: an `#[unstable]` annotation here has no effect
25+
impl Moo for Bar {}
26+
27+
#[unstable(feature = "feat_foo", issue = "none" )]
28+
#[unstable_feature_bound(feat_foo)]
29+
impl Foo for Bar {}
30+
31+
32+
#[unstable(feature = "feat_foo", issue = "none" )]
33+
#[unstable_feature_bound(feat_foo, feat_bar)]
34+
impl Boo for Bar {}
35+
36+
fn main() {}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
error: an `#[unstable]` annotation here has no effect
2+
--> $DIR/unstable-feature-bound-no-effect.rs:23:1
3+
|
4+
LL | #[unstable(feature = "feat_moo", issue = "none" )]
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: see issue #55436 <https://github.com/rust-lang/rust/issues/55436> for more information
8+
= note: `#[deny(ineffective_unstable_trait_impl)]` on by default
9+
10+
error: module has missing stability attribute
11+
--> $DIR/unstable-feature-bound-no-effect.rs:1:1
12+
|
13+
LL | / #![allow(internal_features)]
14+
LL | |
15+
LL | | #![feature(staged_api)]
16+
LL | | #![feature(impl_stability)]
17+
... |
18+
LL | | fn main() {}
19+
| |____________^
20+
21+
error: aborting due to 2 previous errors
22+

0 commit comments

Comments
 (0)