Skip to content

Commit 9891908

Browse files
committed
Auto merge of rust-lang#76538 - fusion-engineering-forks:check-useless-unstable-trait-impl, r=lcnr
Warn for #[unstable] on trait impls when it has no effect. Earlier today I sent a PR with an `#[unstable]` attribute on a trait `impl`, but was informed that this attribute has no effect there. (comment: rust-lang#76525 (comment), issue: rust-lang#55436) This PR adds a warning for this situation. Trait `impl` blocks with `#[unstable]` where both the type and the trait are stable will result in a warning: ``` warning: An `#[unstable]` annotation here has no effect. See issue rust-lang#55436 <rust-lang#55436> for more information. --> library/std/src/panic.rs:235:1 | 235 | #[unstable(feature = "integer_atomics", issue = "32976")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ``` --- It detects three problems in the existing code: 1. A few `RefUnwindSafe` implementations for the atomic integer types in `library/std/src/panic.rs`. Example: https://github.com/rust-lang/rust/blob/d92155bf6ae0b7d79fc83cbeeb0cc0c765353471/library/std/src/panic.rs#L235-L236 2. An implementation of `Error` for `LayoutErr` in `library/std/srd/error.rs`: https://github.com/rust-lang/rust/blob/d92155bf6ae0b7d79fc83cbeeb0cc0c765353471/library/std/src/error.rs#L392-L397 3. `From` implementations for `Waker` and `RawWaker` in `library/alloc/src/task.rs`. Example: https://github.com/rust-lang/rust/blob/d92155bf6ae0b7d79fc83cbeeb0cc0c765353471/library/alloc/src/task.rs#L36-L37 Case 3 interesting: It has a bound with an `#[unstable]` trait (`W: Wake`), so appears to have much effect on stable code. It does however break similar blanket implementations. It would also have immediate effect if `Wake` was implemented for any stable type. (Which is not the case right now, but there are no warnings in place to prevent it.) Whether this case is a problem or not is not clear to me. If it isn't, adding a simple `c.visit_generics(..);` to this PR will stop the warning for this case.
2 parents 7adeb2c + 14cc177 commit 9891908

File tree

7 files changed

+129
-16
lines changed

7 files changed

+129
-16
lines changed

compiler/rustc_passes/src/stability.rs

+71-2
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,14 @@ use rustc_hir as hir;
99
use rustc_hir::def::{DefKind, Res};
1010
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
1111
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
12-
use rustc_hir::{Generics, HirId, Item, StructField, Variant};
12+
use rustc_hir::{Generics, HirId, Item, StructField, TraitRef, Ty, TyKind, Variant};
1313
use rustc_middle::hir::map::Map;
1414
use rustc_middle::middle::privacy::AccessLevels;
1515
use rustc_middle::middle::stability::{DeprecationEntry, Index};
1616
use rustc_middle::ty::query::Providers;
1717
use rustc_middle::ty::TyCtxt;
1818
use rustc_session::lint;
19+
use rustc_session::lint::builtin::INEFFECTIVE_UNSTABLE_TRAIT_IMPL;
1920
use rustc_session::parse::feature_err;
2021
use rustc_session::Session;
2122
use rustc_span::symbol::{sym, Symbol};
@@ -538,7 +539,37 @@ impl Visitor<'tcx> for Checker<'tcx> {
538539
// For implementations of traits, check the stability of each item
539540
// individually as it's possible to have a stable trait with unstable
540541
// items.
541-
hir::ItemKind::Impl { of_trait: Some(ref t), items, .. } => {
542+
hir::ItemKind::Impl { of_trait: Some(ref t), self_ty, items, .. } => {
543+
if self.tcx.features().staged_api {
544+
// If this impl block has an #[unstable] attribute, give an
545+
// error if all involved types and traits are stable, because
546+
// it will have no effect.
547+
// See: https://github.com/rust-lang/rust/issues/55436
548+
if let (Some(Stability { level: attr::Unstable { .. }, .. }), _) =
549+
attr::find_stability(&self.tcx.sess, &item.attrs, item.span)
550+
{
551+
let mut c = CheckTraitImplStable { tcx: self.tcx, fully_stable: true };
552+
c.visit_ty(self_ty);
553+
c.visit_trait_ref(t);
554+
if c.fully_stable {
555+
let span = item
556+
.attrs
557+
.iter()
558+
.find(|a| a.has_name(sym::unstable))
559+
.map_or(item.span, |a| a.span);
560+
self.tcx.struct_span_lint_hir(
561+
INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
562+
item.hir_id,
563+
span,
564+
|lint| lint
565+
.build("an `#[unstable]` annotation here has no effect")
566+
.note("see issue #55436 <https://github.com/rust-lang/rust/issues/55436> for more information")
567+
.emit()
568+
);
569+
}
570+
}
571+
}
572+
542573
if let Res::Def(DefKind::Trait, trait_did) = t.path.res {
543574
for impl_item_ref in items {
544575
let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
@@ -598,6 +629,44 @@ impl Visitor<'tcx> for Checker<'tcx> {
598629
}
599630
}
600631

632+
struct CheckTraitImplStable<'tcx> {
633+
tcx: TyCtxt<'tcx>,
634+
fully_stable: bool,
635+
}
636+
637+
impl Visitor<'tcx> for CheckTraitImplStable<'tcx> {
638+
type Map = Map<'tcx>;
639+
640+
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
641+
NestedVisitorMap::None
642+
}
643+
644+
fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, _id: hir::HirId) {
645+
if let Some(def_id) = path.res.opt_def_id() {
646+
if let Some(stab) = self.tcx.lookup_stability(def_id) {
647+
self.fully_stable &= stab.level.is_stable();
648+
}
649+
}
650+
intravisit::walk_path(self, path)
651+
}
652+
653+
fn visit_trait_ref(&mut self, t: &'tcx TraitRef<'tcx>) {
654+
if let Res::Def(DefKind::Trait, trait_did) = t.path.res {
655+
if let Some(stab) = self.tcx.lookup_stability(trait_did) {
656+
self.fully_stable &= stab.level.is_stable();
657+
}
658+
}
659+
intravisit::walk_trait_ref(self, t)
660+
}
661+
662+
fn visit_ty(&mut self, t: &'tcx Ty<'tcx>) {
663+
if let TyKind::Never = t.kind {
664+
self.fully_stable = false;
665+
}
666+
intravisit::walk_ty(self, t)
667+
}
668+
}
669+
601670
/// Given the list of enabled features that were not language features (i.e., that
602671
/// were expected to be library features), and the list of features used from
603672
/// libraries, identify activated features that don't exist and error about them.

compiler/rustc_session/src/lint/builtin.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
//! lints are all available in `rustc_lint::builtin`.
66
77
use crate::lint::FutureIncompatibleInfo;
8-
use crate::{declare_lint, declare_lint_pass};
8+
use crate::{declare_lint, declare_lint_pass, declare_tool_lint};
99
use rustc_span::edition::Edition;
1010
use rustc_span::symbol::sym;
1111

@@ -555,6 +555,12 @@ declare_lint! {
555555
};
556556
}
557557

558+
declare_tool_lint! {
559+
pub rustc::INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
560+
Deny,
561+
"detects `#[unstable]` on stable trait implementations for stable types"
562+
}
563+
558564
declare_lint_pass! {
559565
/// Does nothing as a lint pass, but registers some `Lint`s
560566
/// that are used by other parts of the compiler.
@@ -630,6 +636,7 @@ declare_lint_pass! {
630636
INCOMPLETE_INCLUDE,
631637
CENUM_IMPL_DROP_CAST,
632638
CONST_EVALUATABLE_UNCHECKED,
639+
INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
633640
]
634641
}
635642

library/alloc/src/task.rs

+2
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ pub trait Wake {
3333
}
3434
}
3535

36+
#[allow(rustc::ineffective_unstable_trait_impl)]
3637
#[unstable(feature = "wake_trait", issue = "69912")]
3738
impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for Waker {
3839
fn from(waker: Arc<W>) -> Waker {
@@ -42,6 +43,7 @@ impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for Waker {
4243
}
4344
}
4445

46+
#[allow(rustc::ineffective_unstable_trait_impl)]
4547
#[unstable(feature = "wake_trait", issue = "69912")]
4648
impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for RawWaker {
4749
fn from(waker: Arc<W>) -> RawWaker {

library/std/src/error.rs

+1-5
Original file line numberDiff line numberDiff line change
@@ -389,11 +389,7 @@ impl Error for ! {}
389389
)]
390390
impl Error for AllocErr {}
391391

392-
#[unstable(
393-
feature = "allocator_api",
394-
reason = "the precise API and guarantees it provides may be tweaked.",
395-
issue = "32838"
396-
)]
392+
#[stable(feature = "alloc_layout", since = "1.28.0")]
397393
impl Error for LayoutErr {}
398394

399395
#[stable(feature = "rust1", since = "1.0.0")]

library/std/src/panic.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -232,16 +232,16 @@ impl<T: ?Sized> RefUnwindSafe for RwLock<T> {}
232232
#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")]
233233
impl RefUnwindSafe for atomic::AtomicIsize {}
234234
#[cfg(target_has_atomic_load_store = "8")]
235-
#[unstable(feature = "integer_atomics", issue = "32976")]
235+
#[stable(feature = "integer_atomics_stable", since = "1.34.0")]
236236
impl RefUnwindSafe for atomic::AtomicI8 {}
237237
#[cfg(target_has_atomic_load_store = "16")]
238-
#[unstable(feature = "integer_atomics", issue = "32976")]
238+
#[stable(feature = "integer_atomics_stable", since = "1.34.0")]
239239
impl RefUnwindSafe for atomic::AtomicI16 {}
240240
#[cfg(target_has_atomic_load_store = "32")]
241-
#[unstable(feature = "integer_atomics", issue = "32976")]
241+
#[stable(feature = "integer_atomics_stable", since = "1.34.0")]
242242
impl RefUnwindSafe for atomic::AtomicI32 {}
243243
#[cfg(target_has_atomic_load_store = "64")]
244-
#[unstable(feature = "integer_atomics", issue = "32976")]
244+
#[stable(feature = "integer_atomics_stable", since = "1.34.0")]
245245
impl RefUnwindSafe for atomic::AtomicI64 {}
246246
#[cfg(target_has_atomic_load_store = "128")]
247247
#[unstable(feature = "integer_atomics", issue = "32976")]
@@ -251,16 +251,16 @@ impl RefUnwindSafe for atomic::AtomicI128 {}
251251
#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")]
252252
impl RefUnwindSafe for atomic::AtomicUsize {}
253253
#[cfg(target_has_atomic_load_store = "8")]
254-
#[unstable(feature = "integer_atomics", issue = "32976")]
254+
#[stable(feature = "integer_atomics_stable", since = "1.34.0")]
255255
impl RefUnwindSafe for atomic::AtomicU8 {}
256256
#[cfg(target_has_atomic_load_store = "16")]
257-
#[unstable(feature = "integer_atomics", issue = "32976")]
257+
#[stable(feature = "integer_atomics_stable", since = "1.34.0")]
258258
impl RefUnwindSafe for atomic::AtomicU16 {}
259259
#[cfg(target_has_atomic_load_store = "32")]
260-
#[unstable(feature = "integer_atomics", issue = "32976")]
260+
#[stable(feature = "integer_atomics_stable", since = "1.34.0")]
261261
impl RefUnwindSafe for atomic::AtomicU32 {}
262262
#[cfg(target_has_atomic_load_store = "64")]
263-
#[unstable(feature = "integer_atomics", issue = "32976")]
263+
#[stable(feature = "integer_atomics_stable", since = "1.34.0")]
264264
impl RefUnwindSafe for atomic::AtomicU64 {}
265265
#[cfg(target_has_atomic_load_store = "128")]
266266
#[unstable(feature = "integer_atomics", issue = "32976")]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#![feature(staged_api)]
2+
3+
#[stable(feature = "x", since = "1")]
4+
struct StableType;
5+
6+
#[unstable(feature = "x", issue = "none")]
7+
struct UnstableType;
8+
9+
#[stable(feature = "x", since = "1")]
10+
trait StableTrait {}
11+
12+
#[unstable(feature = "x", issue = "none")]
13+
trait UnstableTrait {}
14+
15+
#[unstable(feature = "x", issue = "none")]
16+
impl UnstableTrait for UnstableType {}
17+
18+
#[unstable(feature = "x", issue = "none")]
19+
impl StableTrait for UnstableType {}
20+
21+
#[unstable(feature = "x", issue = "none")]
22+
impl UnstableTrait for StableType {}
23+
24+
#[unstable(feature = "x", issue = "none")]
25+
//~^ ERROR an `#[unstable]` annotation here has no effect [rustc::ineffective_unstable_trait_impl]
26+
impl StableTrait for StableType {}
27+
28+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error: an `#[unstable]` annotation here has no effect
2+
--> $DIR/stability-attribute-trait-impl.rs:24:1
3+
|
4+
LL | #[unstable(feature = "x", issue = "none")]
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: `#[deny(rustc::ineffective_unstable_trait_impl)]` on by default
8+
= note: see issue #55436 <https://github.com/rust-lang/rust/issues/55436> for more information
9+
10+
error: aborting due to previous error
11+

0 commit comments

Comments
 (0)