Skip to content
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

Warn for #[unstable] on trait impls when it has no effect. #76538

73 changes: 71 additions & 2 deletions compiler/rustc_passes/src/stability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@ use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_hir::{Generics, HirId, Item, StructField, Variant};
use rustc_hir::{Generics, HirId, Item, StructField, TraitRef, Ty, TyKind, Variant};
use rustc_middle::hir::map::Map;
use rustc_middle::middle::privacy::AccessLevels;
use rustc_middle::middle::stability::{DeprecationEntry, Index};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_session::lint;
use rustc_session::lint::builtin::INEFFECTIVE_UNSTABLE_TRAIT_IMPL;
use rustc_session::parse::feature_err;
use rustc_session::Session;
use rustc_span::symbol::{sym, Symbol};
Expand Down Expand Up @@ -538,7 +539,37 @@ impl Visitor<'tcx> for Checker<'tcx> {
// For implementations of traits, check the stability of each item
// individually as it's possible to have a stable trait with unstable
// items.
hir::ItemKind::Impl { of_trait: Some(ref t), items, .. } => {
hir::ItemKind::Impl { of_trait: Some(ref t), self_ty, items, .. } => {
if self.tcx.features().staged_api {
// 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
if let (Some(Stability { level: attr::Unstable { .. }, .. }), _) =
attr::find_stability(&self.tcx.sess, &item.attrs, item.span)
{
let mut c = CheckTraitImplStable { tcx: self.tcx, fully_stable: true };
c.visit_ty(self_ty);
c.visit_trait_ref(t);
if c.fully_stable {
let span = item
.attrs
.iter()
.find(|a| a.has_name(sym::unstable))
.map_or(item.span, |a| a.span);
self.tcx.struct_span_lint_hir(
INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
item.hir_id,
span,
|lint| lint
.build("an `#[unstable]` annotation here has no effect")
.note("see issue #55436 <https://github.com/rust-lang/rust/issues/55436> for more information")
.emit()
);
}
}
}

if let Res::Def(DefKind::Trait, trait_did) = t.path.res {
for impl_item_ref in items {
let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
Expand Down Expand Up @@ -598,6 +629,44 @@ impl Visitor<'tcx> for Checker<'tcx> {
}
}

struct CheckTraitImplStable<'tcx> {
tcx: TyCtxt<'tcx>,
fully_stable: bool,
}

impl Visitor<'tcx> for CheckTraitImplStable<'tcx> {
type Map = Map<'tcx>;

fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
NestedVisitorMap::None
}

fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, _id: hir::HirId) {
if let Some(def_id) = path.res.opt_def_id() {
if let Some(stab) = self.tcx.lookup_stability(def_id) {
self.fully_stable &= stab.level.is_stable();
}
}
intravisit::walk_path(self, path)
}

fn visit_trait_ref(&mut self, t: &'tcx TraitRef<'tcx>) {
if let Res::Def(DefKind::Trait, trait_did) = t.path.res {
if let Some(stab) = self.tcx.lookup_stability(trait_did) {
self.fully_stable &= stab.level.is_stable();
}
}
intravisit::walk_trait_ref(self, t)
}

fn visit_ty(&mut self, t: &'tcx Ty<'tcx>) {
if let TyKind::Never = t.kind {
self.fully_stable = false;
}
intravisit::walk_ty(self, t)
}
}

/// Given the list of enabled features that were not language features (i.e., that
/// were expected to be library features), and the list of features used from
/// libraries, identify activated features that don't exist and error about them.
Expand Down
9 changes: 8 additions & 1 deletion compiler/rustc_session/src/lint/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
//! lints are all available in `rustc_lint::builtin`.

use crate::lint::FutureIncompatibleInfo;
use crate::{declare_lint, declare_lint_pass};
use crate::{declare_lint, declare_lint_pass, declare_tool_lint};
use rustc_span::edition::Edition;
use rustc_span::symbol::sym;

Expand Down Expand Up @@ -555,6 +555,12 @@ declare_lint! {
};
}

declare_tool_lint! {
pub rustc::INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
Deny,
"detects `#[unstable]` on stable trait implementations for stable types"
}

declare_lint_pass! {
/// Does nothing as a lint pass, but registers some `Lint`s
/// that are used by other parts of the compiler.
Expand Down Expand Up @@ -630,6 +636,7 @@ declare_lint_pass! {
INCOMPLETE_INCLUDE,
CENUM_IMPL_DROP_CAST,
CONST_EVALUATABLE_UNCHECKED,
INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
]
}

Expand Down
2 changes: 2 additions & 0 deletions library/alloc/src/task.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ pub trait Wake {
}
}

#[allow(rustc::ineffective_unstable_trait_impl)]
m-ou-se marked this conversation as resolved.
Show resolved Hide resolved
#[unstable(feature = "wake_trait", issue = "69912")]
impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for Waker {
fn from(waker: Arc<W>) -> Waker {
Expand All @@ -42,6 +43,7 @@ impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for Waker {
}
}

#[allow(rustc::ineffective_unstable_trait_impl)]
#[unstable(feature = "wake_trait", issue = "69912")]
impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for RawWaker {
fn from(waker: Arc<W>) -> RawWaker {
Expand Down
6 changes: 1 addition & 5 deletions library/std/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -389,11 +389,7 @@ impl Error for ! {}
)]
impl Error for AllocErr {}

#[unstable(
feature = "allocator_api",
reason = "the precise API and guarantees it provides may be tweaked.",
issue = "32838"
)]
#[stable(feature = "alloc_layout", since = "1.28.0")]
impl Error for LayoutErr {}

#[stable(feature = "rust1", since = "1.0.0")]
Expand Down
16 changes: 8 additions & 8 deletions library/std/src/panic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,16 +232,16 @@ impl<T: ?Sized> RefUnwindSafe for RwLock<T> {}
#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")]
impl RefUnwindSafe for atomic::AtomicIsize {}
#[cfg(target_has_atomic_load_store = "8")]
#[unstable(feature = "integer_atomics", issue = "32976")]
#[stable(feature = "integer_atomics_stable", since = "1.34.0")]
impl RefUnwindSafe for atomic::AtomicI8 {}
#[cfg(target_has_atomic_load_store = "16")]
#[unstable(feature = "integer_atomics", issue = "32976")]
#[stable(feature = "integer_atomics_stable", since = "1.34.0")]
impl RefUnwindSafe for atomic::AtomicI16 {}
#[cfg(target_has_atomic_load_store = "32")]
#[unstable(feature = "integer_atomics", issue = "32976")]
#[stable(feature = "integer_atomics_stable", since = "1.34.0")]
impl RefUnwindSafe for atomic::AtomicI32 {}
#[cfg(target_has_atomic_load_store = "64")]
#[unstable(feature = "integer_atomics", issue = "32976")]
#[stable(feature = "integer_atomics_stable", since = "1.34.0")]
impl RefUnwindSafe for atomic::AtomicI64 {}
#[cfg(target_has_atomic_load_store = "128")]
#[unstable(feature = "integer_atomics", issue = "32976")]
Expand All @@ -251,16 +251,16 @@ impl RefUnwindSafe for atomic::AtomicI128 {}
#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")]
impl RefUnwindSafe for atomic::AtomicUsize {}
#[cfg(target_has_atomic_load_store = "8")]
#[unstable(feature = "integer_atomics", issue = "32976")]
#[stable(feature = "integer_atomics_stable", since = "1.34.0")]
impl RefUnwindSafe for atomic::AtomicU8 {}
#[cfg(target_has_atomic_load_store = "16")]
#[unstable(feature = "integer_atomics", issue = "32976")]
#[stable(feature = "integer_atomics_stable", since = "1.34.0")]
impl RefUnwindSafe for atomic::AtomicU16 {}
#[cfg(target_has_atomic_load_store = "32")]
#[unstable(feature = "integer_atomics", issue = "32976")]
#[stable(feature = "integer_atomics_stable", since = "1.34.0")]
impl RefUnwindSafe for atomic::AtomicU32 {}
#[cfg(target_has_atomic_load_store = "64")]
#[unstable(feature = "integer_atomics", issue = "32976")]
#[stable(feature = "integer_atomics_stable", since = "1.34.0")]
impl RefUnwindSafe for atomic::AtomicU64 {}
#[cfg(target_has_atomic_load_store = "128")]
#[unstable(feature = "integer_atomics", issue = "32976")]
Expand Down
28 changes: 28 additions & 0 deletions src/test/ui/stability-attribute/stability-attribute-trait-impl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#![feature(staged_api)]

#[stable(feature = "x", since = "1")]
struct StableType;

#[unstable(feature = "x", issue = "none")]
struct UnstableType;

#[stable(feature = "x", since = "1")]
trait StableTrait {}

#[unstable(feature = "x", issue = "none")]
trait UnstableTrait {}

#[unstable(feature = "x", issue = "none")]
impl UnstableTrait for UnstableType {}

#[unstable(feature = "x", issue = "none")]
impl StableTrait for UnstableType {}

#[unstable(feature = "x", issue = "none")]
impl UnstableTrait for StableType {}

#[unstable(feature = "x", issue = "none")]
//~^ ERROR an `#[unstable]` annotation here has no effect [rustc::ineffective_unstable_trait_impl]
impl StableTrait for StableType {}

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
error: an `#[unstable]` annotation here has no effect
--> $DIR/stability-attribute-trait-impl.rs:24:1
|
LL | #[unstable(feature = "x", issue = "none")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[deny(rustc::ineffective_unstable_trait_impl)]` on by default
= note: see issue #55436 <https://github.com/rust-lang/rust/issues/55436> for more information

error: aborting due to previous error