1 //! A pass that annotates every item and method with its stability level,
2 //! propagating default levels lexically from parent to children ast nodes.
5 self, CannotStabilizeDeprecated
, DeprecatedAttribute
, DuplicateFeatureErr
,
6 FeatureOnlyOnNightly
, ImpliedFeatureNotExist
, InvalidDeprecationVersion
, InvalidStability
,
7 MissingConstErr
, MissingConstStabAttr
, MissingStabilityAttr
, TraitImplConstStable
,
8 UnknownFeature
, UselessStability
,
11 self as attr
, rust_version_symbol
, ConstStability
, Stability
, StabilityLevel
, Unstable
,
12 UnstableReason
, VERSION_PLACEHOLDER
,
14 use rustc_data_structures
::fx
::{FxHashMap, FxHashSet, FxIndexMap}
;
15 use rustc_errors
::Applicability
;
17 use rustc_hir
::def
::{DefKind, Res}
;
18 use rustc_hir
::def_id
::{LocalDefId, CRATE_DEF_ID}
;
19 use rustc_hir
::hir_id
::CRATE_HIR_ID
;
20 use rustc_hir
::intravisit
::{self, Visitor}
;
21 use rustc_hir
::{FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant}
;
22 use rustc_middle
::hir
::nested_filter
;
23 use rustc_middle
::middle
::privacy
::EffectiveVisibilities
;
24 use rustc_middle
::middle
::stability
::{AllowUnstable, DeprecationEntry, Index}
;
25 use rustc_middle
::ty
::{query::Providers, TyCtxt}
;
26 use rustc_session
::lint
;
27 use rustc_session
::lint
::builtin
::{INEFFECTIVE_UNSTABLE_TRAIT_IMPL, USELESS_DEPRECATED}
;
28 use rustc_span
::symbol
::{sym, Symbol}
;
30 use rustc_target
::spec
::abi
::Abi
;
32 use std
::cmp
::Ordering
;
34 use std
::mem
::replace
;
35 use std
::num
::NonZeroU32
;
39 /// Annotation is required if not inherited from unstable parents.
41 /// Annotation is useless, reject it.
43 /// Deprecation annotation is useless, reject it. (Stability attribute is still required.)
44 DeprecationProhibited
,
45 /// Annotation itself is useless, but it can be propagated to children.
49 /// Whether to inherit deprecation flags for nested items. In most cases, we do want to inherit
50 /// deprecation, because nested items rarely have individual deprecation attributes, and so
51 /// should be treated as deprecated if their parent is. However, default generic parameters
52 /// have separate deprecation attributes from their parents, so we do not wish to inherit
53 /// deprecation in this case. For example, inheriting deprecation for `T` in `Foo<T>`
54 /// would cause a duplicate warning arising from both `Foo` and `T` being deprecated.
56 enum InheritDeprecation
{
61 impl InheritDeprecation
{
62 fn yes(&self) -> bool
{
63 matches
!(self, InheritDeprecation
::Yes
)
67 /// Whether to inherit const stability flags for nested items. In most cases, we do not want to
68 /// inherit const stability: just because an enclosing `fn` is const-stable does not mean
69 /// all `extern` imports declared in it should be const-stable! However, trait methods
70 /// inherit const stability attributes from their parent and do not have their own.
71 enum InheritConstStability
{
76 impl InheritConstStability
{
77 fn yes(&self) -> bool
{
78 matches
!(self, InheritConstStability
::Yes
)
82 enum InheritStability
{
87 impl InheritStability
{
88 fn yes(&self) -> bool
{
89 matches
!(self, InheritStability
::Yes
)
93 /// A private tree-walker for producing an `Index`.
94 struct Annotator
<'a
, 'tcx
> {
97 parent_stab
: Option
<Stability
>,
98 parent_const_stab
: Option
<ConstStability
>,
99 parent_depr
: Option
<DeprecationEntry
>,
103 impl<'a
, 'tcx
> Annotator
<'a
, 'tcx
> {
104 /// Determine the stability for a node based on its attributes and inherited stability. The
105 /// stability is recorded in the index and used as the parent. If the node is a function,
106 /// `fn_sig` is its signature.
111 fn_sig
: Option
<&'tcx hir
::FnSig
<'tcx
>>,
112 kind
: AnnotationKind
,
113 inherit_deprecation
: InheritDeprecation
,
114 inherit_const_stability
: InheritConstStability
,
115 inherit_from_parent
: InheritStability
,
118 F
: FnOnce(&mut Self),
120 let attrs
= self.tcx
.hir().attrs(self.tcx
.hir().local_def_id_to_hir_id(def_id
));
121 debug
!("annotate(id = {:?}, attrs = {:?})", def_id
, attrs
);
123 let depr
= attr
::find_deprecation(&self.tcx
.sess
, attrs
);
124 let mut is_deprecated
= false;
125 if let Some((depr
, span
)) = &depr
{
126 is_deprecated
= true;
128 if kind
== AnnotationKind
::Prohibited
|| kind
== AnnotationKind
::DeprecationProhibited
{
129 let hir_id
= self.tcx
.hir().local_def_id_to_hir_id(def_id
);
130 self.tcx
.emit_spanned_lint(
134 errors
::DeprecatedAnnotationHasNoEffect { span: *span }
,
138 // `Deprecation` is just two pointers, no need to intern it
139 let depr_entry
= DeprecationEntry
::local(*depr
, def_id
);
140 self.index
.depr_map
.insert(def_id
, depr_entry
);
141 } else if let Some(parent_depr
) = self.parent_depr
{
142 if inherit_deprecation
.yes() {
143 is_deprecated
= true;
144 info
!("tagging child {:?} as deprecated from parent", def_id
);
145 self.index
.depr_map
.insert(def_id
, parent_depr
);
149 if !self.tcx
.features().staged_api
{
150 // Propagate unstability. This can happen even for non-staged-api crates in case
151 // -Zforce-unstable-if-unmarked is set.
152 if let Some(stab
) = self.parent_stab
{
153 if inherit_deprecation
.yes() && stab
.is_unstable() {
154 self.index
.stab_map
.insert(def_id
, stab
);
158 self.recurse_with_stability_attrs(
159 depr
.map(|(d
, _
)| DeprecationEntry
::local(d
, def_id
)),
167 let (stab
, const_stab
, body_stab
) = attr
::find_stability(&self.tcx
.sess
, attrs
, item_sp
);
168 let mut const_span
= None
;
170 let const_stab
= const_stab
.map(|(const_stab
, const_span_node
)| {
171 self.index
.const_stab_map
.insert(def_id
, const_stab
);
172 const_span
= Some(const_span_node
);
176 // If the current node is a function, has const stability attributes and if it doesn not have an intrinsic ABI,
177 // check if the function/method is const or the parent impl block is const
178 if let (Some(const_span
), Some(fn_sig
)) = (const_span
, fn_sig
) {
179 if fn_sig
.header
.abi
!= Abi
::RustIntrinsic
180 && fn_sig
.header
.abi
!= Abi
::PlatformIntrinsic
181 && !fn_sig
.header
.is_const()
183 if !self.in_trait_impl
184 || (self.in_trait_impl
&& !self.tcx
.is_const_fn_raw(def_id
.to_def_id()))
188 .emit_err(MissingConstErr { fn_sig_span: fn_sig.span, const_span }
);
193 // `impl const Trait for Type` items forward their const stability to their
194 // immediate children.
195 if const_stab
.is_none() {
196 debug
!("annotate: const_stab not found, parent = {:?}", self.parent_const_stab
);
197 if let Some(parent
) = self.parent_const_stab
{
198 if parent
.is_const_unstable() {
199 self.index
.const_stab_map
.insert(def_id
, parent
);
204 if let Some((rustc_attr
::Deprecation { is_since_rustc_version: true, .. }
, span
)) = &depr
{
206 self.tcx
.sess
.emit_err(DeprecatedAttribute { span: *span }
);
210 if let Some((body_stab
, _span
)) = body_stab
{
211 // FIXME: check that this item can have body stability
213 self.index
.default_body_stab_map
.insert(def_id
, body_stab
);
214 debug
!(?
self.index
.default_body_stab_map
);
217 let stab
= stab
.map(|(stab
, span
)| {
218 // Error if prohibited, or can't inherit anything from a container.
219 if kind
== AnnotationKind
::Prohibited
220 || (kind
== AnnotationKind
::Container
&& stab
.level
.is_stable() && is_deprecated
)
222 self.tcx
.sess
.emit_err(UselessStability { span, item_sp }
);
225 debug
!("annotate: found {:?}", stab
);
227 // Check if deprecated_since < stable_since. If it is,
228 // this is *almost surely* an accident.
229 if let (&Some(dep_since
), &attr
::Stable { since: stab_since, .. }
) =
230 (&depr
.as_ref().and_then(|(d
, _
)| d
.since
), &stab
.level
)
232 // Explicit version of iter::order::lt to handle parse errors properly
233 for (dep_v
, stab_v
) in
234 iter
::zip(dep_since
.as_str().split('
.'
), stab_since
.as_str().split('
.'
))
236 match stab_v
.parse
::<u64>() {
238 self.tcx
.sess
.emit_err(InvalidStability { span, item_sp }
);
241 Ok(stab_vp
) => match dep_v
.parse
::<u64>() {
242 Ok(dep_vp
) => match dep_vp
.cmp(&stab_vp
) {
246 .emit_err(CannotStabilizeDeprecated { span, item_sp }
);
249 Ordering
::Equal
=> continue,
250 Ordering
::Greater
=> break,
256 .emit_err(InvalidDeprecationVersion { span, item_sp }
);
265 if let Stability { level: Unstable { implied_by: Some(implied_by), .. }
, feature
} =
268 self.index
.implications
.insert(implied_by
, feature
);
271 self.index
.stab_map
.insert(def_id
, stab
);
276 debug
!("annotate: stab not found, parent = {:?}", self.parent_stab
);
277 if let Some(stab
) = self.parent_stab
{
278 if inherit_deprecation
.yes() && stab
.is_unstable() || inherit_from_parent
.yes() {
279 self.index
.stab_map
.insert(def_id
, stab
);
284 self.recurse_with_stability_attrs(
285 depr
.map(|(d
, _
)| DeprecationEntry
::local(d
, def_id
)),
287 if inherit_const_stability
.yes() { const_stab }
else { None }
,
292 fn recurse_with_stability_attrs(
294 depr
: Option
<DeprecationEntry
>,
295 stab
: Option
<Stability
>,
296 const_stab
: Option
<ConstStability
>,
297 f
: impl FnOnce(&mut Self),
299 // These will be `Some` if this item changes the corresponding stability attribute.
300 let mut replaced_parent_depr
= None
;
301 let mut replaced_parent_stab
= None
;
302 let mut replaced_parent_const_stab
= None
;
304 if let Some(depr
) = depr
{
305 replaced_parent_depr
= Some(replace(&mut self.parent_depr
, Some(depr
)));
307 if let Some(stab
) = stab
{
308 replaced_parent_stab
= Some(replace(&mut self.parent_stab
, Some(stab
)));
310 if let Some(const_stab
) = const_stab
{
311 replaced_parent_const_stab
=
312 Some(replace(&mut self.parent_const_stab
, Some(const_stab
)));
317 if let Some(orig_parent_depr
) = replaced_parent_depr
{
318 self.parent_depr
= orig_parent_depr
;
320 if let Some(orig_parent_stab
) = replaced_parent_stab
{
321 self.parent_stab
= orig_parent_stab
;
323 if let Some(orig_parent_const_stab
) = replaced_parent_const_stab
{
324 self.parent_const_stab
= orig_parent_const_stab
;
329 impl<'a
, 'tcx
> Visitor
<'tcx
> for Annotator
<'a
, 'tcx
> {
330 /// Because stability levels are scoped lexically, we want to walk
331 /// nested items in the context of the outer item, so enable
333 type NestedFilter
= nested_filter
::All
;
335 fn nested_visit_map(&mut self) -> Self::Map
{
339 fn visit_item(&mut self, i
: &'tcx Item
<'tcx
>) {
340 let orig_in_trait_impl
= self.in_trait_impl
;
341 let mut kind
= AnnotationKind
::Required
;
342 let mut const_stab_inherit
= InheritConstStability
::No
;
343 let mut fn_sig
= None
;
346 // Inherent impls and foreign modules serve only as containers for other items,
347 // they don't have their own stability. They still can be annotated as unstable
348 // and propagate this instability to children, but this annotation is completely
349 // optional. They inherit stability from their parents when unannotated.
350 hir
::ItemKind
::Impl(hir
::Impl { of_trait: None, .. }
)
351 | hir
::ItemKind
::ForeignMod { .. }
=> {
352 self.in_trait_impl
= false;
353 kind
= AnnotationKind
::Container
;
355 hir
::ItemKind
::Impl(hir
::Impl { of_trait: Some(_), .. }
) => {
356 self.in_trait_impl
= true;
357 kind
= AnnotationKind
::DeprecationProhibited
;
358 const_stab_inherit
= InheritConstStability
::Yes
;
360 hir
::ItemKind
::Struct(ref sd
, _
) => {
361 if let Some(ctor_hir_id
) = sd
.ctor_hir_id() {
363 self.tcx
.hir().local_def_id(ctor_hir_id
),
366 AnnotationKind
::Required
,
367 InheritDeprecation
::Yes
,
368 InheritConstStability
::No
,
369 InheritStability
::Yes
,
374 hir
::ItemKind
::Fn(ref item_fn_sig
, _
, _
) => {
375 fn_sig
= Some(item_fn_sig
);
385 InheritDeprecation
::Yes
,
387 InheritStability
::No
,
388 |v
| intravisit
::walk_item(v
, i
),
390 self.in_trait_impl
= orig_in_trait_impl
;
393 fn visit_trait_item(&mut self, ti
: &'tcx hir
::TraitItem
<'tcx
>) {
394 let fn_sig
= match ti
.kind
{
395 hir
::TraitItemKind
::Fn(ref fn_sig
, _
) => Some(fn_sig
),
403 AnnotationKind
::Required
,
404 InheritDeprecation
::Yes
,
405 InheritConstStability
::No
,
406 InheritStability
::No
,
408 intravisit
::walk_trait_item(v
, ti
);
413 fn visit_impl_item(&mut self, ii
: &'tcx hir
::ImplItem
<'tcx
>) {
415 if self.in_trait_impl { AnnotationKind::Prohibited }
else { AnnotationKind::Required }
;
417 let fn_sig
= match ii
.kind
{
418 hir
::ImplItemKind
::Fn(ref fn_sig
, _
) => Some(fn_sig
),
427 InheritDeprecation
::Yes
,
428 InheritConstStability
::No
,
429 InheritStability
::No
,
431 intravisit
::walk_impl_item(v
, ii
);
436 fn visit_variant(&mut self, var
: &'tcx Variant
<'tcx
>) {
438 self.tcx
.hir().local_def_id(var
.id
),
441 AnnotationKind
::Required
,
442 InheritDeprecation
::Yes
,
443 InheritConstStability
::No
,
444 InheritStability
::Yes
,
446 if let Some(ctor_hir_id
) = var
.data
.ctor_hir_id() {
448 v
.tcx
.hir().local_def_id(ctor_hir_id
),
451 AnnotationKind
::Required
,
452 InheritDeprecation
::Yes
,
453 InheritConstStability
::No
,
454 InheritStability
::Yes
,
459 intravisit
::walk_variant(v
, var
)
464 fn visit_field_def(&mut self, s
: &'tcx FieldDef
<'tcx
>) {
466 self.tcx
.hir().local_def_id(s
.hir_id
),
469 AnnotationKind
::Required
,
470 InheritDeprecation
::Yes
,
471 InheritConstStability
::No
,
472 InheritStability
::Yes
,
474 intravisit
::walk_field_def(v
, s
);
479 fn visit_foreign_item(&mut self, i
: &'tcx hir
::ForeignItem
<'tcx
>) {
484 AnnotationKind
::Required
,
485 InheritDeprecation
::Yes
,
486 InheritConstStability
::No
,
487 InheritStability
::No
,
489 intravisit
::walk_foreign_item(v
, i
);
494 fn visit_generic_param(&mut self, p
: &'tcx hir
::GenericParam
<'tcx
>) {
495 let kind
= match &p
.kind
{
496 // Allow stability attributes on default generic arguments.
497 hir
::GenericParamKind
::Type { default: Some(_), .. }
498 | hir
::GenericParamKind
::Const { default: Some(_), .. }
=> AnnotationKind
::Container
,
499 _
=> AnnotationKind
::Prohibited
,
503 self.tcx
.hir().local_def_id(p
.hir_id
),
507 InheritDeprecation
::No
,
508 InheritConstStability
::No
,
509 InheritStability
::No
,
511 intravisit
::walk_generic_param(v
, p
);
517 struct MissingStabilityAnnotations
<'tcx
> {
519 effective_visibilities
: &'tcx EffectiveVisibilities
,
522 impl<'tcx
> MissingStabilityAnnotations
<'tcx
> {
523 fn check_missing_stability(&self, def_id
: LocalDefId
, span
: Span
) {
524 let stab
= self.tcx
.stability().local_stability(def_id
);
525 if !self.tcx
.sess
.opts
.test
527 && self.effective_visibilities
.is_reachable(def_id
)
529 let descr
= self.tcx
.def_kind(def_id
).descr(def_id
.to_def_id());
530 self.tcx
.sess
.emit_err(MissingStabilityAttr { span, descr }
);
534 fn check_missing_const_stability(&self, def_id
: LocalDefId
, span
: Span
) {
535 if !self.tcx
.features().staged_api
{
539 let is_const
= self.tcx
.is_const_fn(def_id
.to_def_id())
540 || self.tcx
.is_const_trait_impl_raw(def_id
.to_def_id());
543 .lookup_stability(def_id
)
544 .map_or(false, |stability
| stability
.level
.is_stable());
545 let missing_const_stability_attribute
= self.tcx
.lookup_const_stability(def_id
).is_none();
546 let is_reachable
= self.effective_visibilities
.is_reachable(def_id
);
548 if is_const
&& is_stable
&& missing_const_stability_attribute
&& is_reachable
{
549 let descr
= self.tcx
.def_kind(def_id
).descr(def_id
.to_def_id());
550 self.tcx
.sess
.emit_err(MissingConstStabAttr { span, descr }
);
555 impl<'tcx
> Visitor
<'tcx
> for MissingStabilityAnnotations
<'tcx
> {
556 type NestedFilter
= nested_filter
::OnlyBodies
;
558 fn nested_visit_map(&mut self) -> Self::Map
{
562 fn visit_item(&mut self, i
: &'tcx Item
<'tcx
>) {
563 // Inherent impls and foreign modules serve only as containers for other items,
564 // they don't have their own stability. They still can be annotated as unstable
565 // and propagate this instability to children, but this annotation is completely
566 // optional. They inherit stability from their parents when unannotated.
569 hir
::ItemKind
::Impl(hir
::Impl { of_trait: None, .. }
)
570 | hir
::ItemKind
::ForeignMod { .. }
572 self.check_missing_stability(i
.owner_id
.def_id
, i
.span
);
575 // Ensure stable `const fn` have a const stability attribute.
576 self.check_missing_const_stability(i
.owner_id
.def_id
, i
.span
);
578 intravisit
::walk_item(self, i
)
581 fn visit_trait_item(&mut self, ti
: &'tcx hir
::TraitItem
<'tcx
>) {
582 self.check_missing_stability(ti
.owner_id
.def_id
, ti
.span
);
583 intravisit
::walk_trait_item(self, ti
);
586 fn visit_impl_item(&mut self, ii
: &'tcx hir
::ImplItem
<'tcx
>) {
587 let impl_def_id
= self.tcx
.hir().get_parent_item(ii
.hir_id());
588 if self.tcx
.impl_trait_ref(impl_def_id
).is_none() {
589 self.check_missing_stability(ii
.owner_id
.def_id
, ii
.span
);
590 self.check_missing_const_stability(ii
.owner_id
.def_id
, ii
.span
);
592 intravisit
::walk_impl_item(self, ii
);
595 fn visit_variant(&mut self, var
: &'tcx Variant
<'tcx
>) {
596 self.check_missing_stability(self.tcx
.hir().local_def_id(var
.id
), var
.span
);
597 if let Some(ctor_hir_id
) = var
.data
.ctor_hir_id() {
598 self.check_missing_stability(self.tcx
.hir().local_def_id(ctor_hir_id
), var
.span
);
600 intravisit
::walk_variant(self, var
);
603 fn visit_field_def(&mut self, s
: &'tcx FieldDef
<'tcx
>) {
604 self.check_missing_stability(self.tcx
.hir().local_def_id(s
.hir_id
), s
.span
);
605 intravisit
::walk_field_def(self, s
);
608 fn visit_foreign_item(&mut self, i
: &'tcx hir
::ForeignItem
<'tcx
>) {
609 self.check_missing_stability(i
.owner_id
.def_id
, i
.span
);
610 intravisit
::walk_foreign_item(self, i
);
612 // Note that we don't need to `check_missing_stability` for default generic parameters,
613 // as we assume that any default generic parameters without attributes are automatically
614 // stable (assuming they have not inherited instability from their parent).
617 fn stability_index(tcx
: TyCtxt
<'_
>, (): ()) -> Index
{
618 let mut index
= Index
{
619 stab_map
: Default
::default(),
620 const_stab_map
: Default
::default(),
621 default_body_stab_map
: Default
::default(),
622 depr_map
: Default
::default(),
623 implications
: Default
::default(),
627 let mut annotator
= Annotator
{
631 parent_const_stab
: None
,
633 in_trait_impl
: false,
636 // If the `-Z force-unstable-if-unmarked` flag is passed then we provide
637 // a parent stability annotation which indicates that this is private
638 // with the `rustc_private` feature. This is intended for use when
639 // compiling `librustc_*` crates themselves so we can leverage crates.io
640 // while maintaining the invariant that all sysroot crates are unstable
641 // by default and are unable to be used.
642 if tcx
.sess
.opts
.unstable_opts
.force_unstable_if_unmarked
{
643 let stability
= Stability
{
644 level
: attr
::StabilityLevel
::Unstable
{
645 reason
: UnstableReason
::Default
,
646 issue
: NonZeroU32
::new(27812),
650 feature
: sym
::rustc_private
,
652 annotator
.parent_stab
= Some(stability
);
657 tcx
.hir().span(CRATE_HIR_ID
),
659 AnnotationKind
::Required
,
660 InheritDeprecation
::Yes
,
661 InheritConstStability
::No
,
662 InheritStability
::No
,
663 |v
| tcx
.hir().walk_toplevel_module(v
),
669 /// Cross-references the feature names of unstable APIs with enabled
670 /// features and possibly prints errors.
671 fn check_mod_unstable_api_usage(tcx
: TyCtxt
<'_
>, module_def_id
: LocalDefId
) {
672 tcx
.hir().visit_item_likes_in_module(module_def_id
, &mut Checker { tcx }
);
675 pub(crate) fn provide(providers
: &mut Providers
) {
676 *providers
= Providers
{
677 check_mod_unstable_api_usage
,
679 stability_implications
: |tcx
, _
| tcx
.stability().implications
.clone(),
680 lookup_stability
: |tcx
, id
| tcx
.stability().local_stability(id
.expect_local()),
681 lookup_const_stability
: |tcx
, id
| tcx
.stability().local_const_stability(id
.expect_local()),
682 lookup_default_body_stability
: |tcx
, id
| {
683 tcx
.stability().local_default_body_stability(id
.expect_local())
685 lookup_deprecation_entry
: |tcx
, id
| {
686 tcx
.stability().local_deprecation_entry(id
.expect_local())
692 struct Checker
<'tcx
> {
696 impl<'tcx
> Visitor
<'tcx
> for Checker
<'tcx
> {
697 type NestedFilter
= nested_filter
::OnlyBodies
;
699 /// Because stability levels are scoped lexically, we want to walk
700 /// nested items in the context of the outer item, so enable
702 fn nested_visit_map(&mut self) -> Self::Map
{
706 fn visit_item(&mut self, item
: &'tcx hir
::Item
<'tcx
>) {
708 hir
::ItemKind
::ExternCrate(_
) => {
709 // compiler-generated `extern crate` items have a dummy span.
710 // `std` is still checked for the `restricted-std` feature.
711 if item
.span
.is_dummy() && item
.ident
.name
!= sym
::std
{
715 let Some(cnum
) = self.tcx
.extern_mod_stmt_cnum(item
.owner_id
.def_id
) else {
718 let def_id
= cnum
.as_def_id();
719 self.tcx
.check_stability(def_id
, Some(item
.hir_id()), item
.span
, None
);
722 // For implementations of traits, check the stability of each item
723 // individually as it's possible to have a stable trait with unstable
725 hir
::ItemKind
::Impl(hir
::Impl
{
726 of_trait
: Some(ref t
),
732 let features
= self.tcx
.features();
733 if features
.staged_api
{
734 let attrs
= self.tcx
.hir().attrs(item
.hir_id());
735 let (stab
, const_stab
, _
) =
736 attr
::find_stability(&self.tcx
.sess
, attrs
, item
.span
);
738 // If this impl block has an #[unstable] attribute, give an
739 // error if all involved types and traits are stable, because
740 // it will have no effect.
741 // See: https://github.com/rust-lang/rust/issues/55436
742 if let Some((Stability { level: attr::Unstable { .. }
, .. }, span
)) = stab
{
743 let mut c
= CheckTraitImplStable { tcx: self.tcx, fully_stable: true }
;
745 c
.visit_trait_ref(t
);
747 self.tcx
.struct_span_lint_hir(
748 INEFFECTIVE_UNSTABLE_TRAIT_IMPL
,
751 "an `#[unstable]` annotation here has no effect",
752 |lint
| lint
.note("see issue #55436 <https://github.com/rust-lang/rust/issues/55436> for more information")
757 // `#![feature(const_trait_impl)]` is unstable, so any impl declared stable
758 // needs to have an error emitted.
759 if features
.const_trait_impl
760 && *constness
== hir
::Constness
::Const
761 && const_stab
.map_or(false, |(stab
, _
)| stab
.is_const_stable())
763 self.tcx
.sess
.emit_err(TraitImplConstStable { span: item.span }
);
767 for impl_item_ref
in *items
{
768 let impl_item
= self.tcx
.associated_item(impl_item_ref
.id
.owner_id
);
770 if let Some(def_id
) = impl_item
.trait_item_def_id
{
771 // Pass `None` to skip deprecation warnings.
772 self.tcx
.check_stability(def_id
, None
, impl_item_ref
.span
, None
);
779 intravisit
::walk_item(self, item
);
782 fn visit_path(&mut self, path
: &'tcx hir
::Path
<'tcx
>, id
: hir
::HirId
) {
783 if let Some(def_id
) = path
.res
.opt_def_id() {
784 let method_span
= path
.segments
.last().map(|s
| s
.ident
.span
);
785 let item_is_allowed
= self.tcx
.check_stability_allow_unstable(
790 if is_unstable_reexport(self.tcx
, id
) {
797 let is_allowed_through_unstable_modules
= |def_id
| {
799 .lookup_stability(def_id
)
800 .map(|stab
| match stab
.level
{
801 StabilityLevel
::Stable { allowed_through_unstable_modules, .. }
=> {
802 allowed_through_unstable_modules
809 if item_is_allowed
&& !is_allowed_through_unstable_modules(def_id
) {
810 // Check parent modules stability as well if the item the path refers to is itself
811 // stable. We only emit warnings for unstable path segments if the item is stable
812 // or allowed because stability is often inherited, so the most common case is that
813 // both the segments and the item are unstable behind the same feature flag.
815 // We check here rather than in `visit_path_segment` to prevent visiting the last
816 // path segment twice
818 // We include special cases via #[rustc_allowed_through_unstable_modules] for items
819 // that were accidentally stabilized through unstable paths before this check was
820 // added, such as `core::intrinsics::transmute`
821 let parents
= path
.segments
.iter().rev().skip(1);
822 for path_segment
in parents
{
823 if let Some(def_id
) = path_segment
.res
.opt_def_id() {
824 // use `None` for id to prevent deprecation check
825 self.tcx
.check_stability_allow_unstable(
830 if is_unstable_reexport(self.tcx
, id
) {
841 intravisit
::walk_path(self, path
)
845 /// Check whether a path is a `use` item that has been marked as unstable.
847 /// See issue #94972 for details on why this is a special case
848 fn is_unstable_reexport
<'tcx
>(tcx
: TyCtxt
<'tcx
>, id
: hir
::HirId
) -> bool
{
849 // Get the LocalDefId so we can lookup the item to check the kind.
850 let Some(def_id
) = tcx
.hir().opt_local_def_id(id
) else { return false; }
;
852 let Some(stab
) = tcx
.stability().local_stability(def_id
) else {
856 if stab
.level
.is_stable() {
857 // The re-export is not marked as unstable, don't override
861 // If this is a path that isn't a use, we don't need to do anything special
862 if !matches
!(tcx
.hir().expect_item(def_id
).kind
, ItemKind
::Use(..)) {
869 struct CheckTraitImplStable
<'tcx
> {
874 impl<'tcx
> Visitor
<'tcx
> for CheckTraitImplStable
<'tcx
> {
875 fn visit_path(&mut self, path
: &'tcx hir
::Path
<'tcx
>, _id
: hir
::HirId
) {
876 if let Some(def_id
) = path
.res
.opt_def_id() {
877 if let Some(stab
) = self.tcx
.lookup_stability(def_id
) {
878 self.fully_stable
&= stab
.level
.is_stable();
881 intravisit
::walk_path(self, path
)
884 fn visit_trait_ref(&mut self, t
: &'tcx TraitRef
<'tcx
>) {
885 if let Res
::Def(DefKind
::Trait
, trait_did
) = t
.path
.res
{
886 if let Some(stab
) = self.tcx
.lookup_stability(trait_did
) {
887 self.fully_stable
&= stab
.level
.is_stable();
890 intravisit
::walk_trait_ref(self, t
)
893 fn visit_ty(&mut self, t
: &'tcx Ty
<'tcx
>) {
894 if let TyKind
::Never
= t
.kind
{
895 self.fully_stable
= false;
897 if let TyKind
::BareFn(f
) = t
.kind
{
898 if rustc_target
::spec
::abi
::is_stable(f
.abi
.name()).is_err() {
899 self.fully_stable
= false;
902 intravisit
::walk_ty(self, t
)
905 fn visit_fn_decl(&mut self, fd
: &'tcx hir
::FnDecl
<'tcx
>) {
906 for ty
in fd
.inputs
{
909 if let hir
::FnRetTy
::Return(output_ty
) = fd
.output
{
910 match output_ty
.kind
{
911 TyKind
::Never
=> {}
// `-> !` is stable
912 _
=> self.visit_ty(output_ty
),
918 /// Given the list of enabled features that were not language features (i.e., that
919 /// were expected to be library features), and the list of features used from
920 /// libraries, identify activated features that don't exist and error about them.
921 pub fn check_unused_or_stable_features(tcx
: TyCtxt
<'_
>) {
923 tcx
.sess
.opts
.unstable_opts
.force_unstable_if_unmarked
|| tcx
.features().staged_api
;
925 let effective_visibilities
= &tcx
.effective_visibilities(());
926 let mut missing
= MissingStabilityAnnotations { tcx, effective_visibilities }
;
927 missing
.check_missing_stability(CRATE_DEF_ID
, tcx
.hir().span(CRATE_HIR_ID
));
928 tcx
.hir().walk_toplevel_module(&mut missing
);
929 tcx
.hir().visit_all_item_likes_in_crate(&mut missing
);
932 let declared_lang_features
= &tcx
.features().declared_lang_features
;
933 let mut lang_features
= FxHashSet
::default();
934 for &(feature
, span
, since
) in declared_lang_features
{
935 if let Some(since
) = since
{
936 // Warn if the user has enabled an already-stable lang feature.
937 unnecessary_stable_feature_lint(tcx
, span
, feature
, since
);
939 if !lang_features
.insert(feature
) {
940 // Warn if the user enables a lang feature multiple times.
941 tcx
.sess
.emit_err(DuplicateFeatureErr { span, feature }
);
945 let declared_lib_features
= &tcx
.features().declared_lib_features
;
946 let mut remaining_lib_features
= FxIndexMap
::default();
947 for (feature
, span
) in declared_lib_features
{
948 if !tcx
.sess
.opts
.unstable_features
.is_nightly_build() {
949 tcx
.sess
.emit_err(FeatureOnlyOnNightly
{
951 release_channel
: env
!("CFG_RELEASE_CHANNEL"),
954 if remaining_lib_features
.contains_key(&feature
) {
955 // Warn if the user enables a lib feature multiple times.
956 tcx
.sess
.emit_err(DuplicateFeatureErr { span: *span, feature: *feature }
);
958 remaining_lib_features
.insert(feature
, *span
);
960 // `stdbuild` has special handling for `libc`, so we need to
961 // recognise the feature when building std.
962 // Likewise, libtest is handled specially, so `test` isn't
963 // available as we'd like it to be.
964 // FIXME: only remove `libc` when `stdbuild` is active.
965 // FIXME: remove special casing for `test`.
966 remaining_lib_features
.remove(&sym
::libc
);
967 remaining_lib_features
.remove(&sym
::test
);
969 /// For each feature in `defined_features`..
971 /// - If it is in `remaining_lib_features` (those features with `#![feature(..)]` attributes in
972 /// the current crate), check if it is stable (or partially stable) and thus an unnecessary
974 /// - If it is in `remaining_implications` (a feature that is referenced by an `implied_by`
975 /// from the current crate), then remove it from the remaining implications.
977 /// Once this function has been invoked for every feature (local crate and all extern crates),
980 /// - If features remain in `remaining_lib_features`, then the user has enabled a feature that
982 /// - If features remain in `remaining_implications`, the `implied_by` refers to a feature that
985 /// By structuring the code in this way: checking the features defined from each crate one at a
986 /// time, less loading from metadata is performed and thus compiler performance is improved.
987 fn check_features
<'tcx
>(
989 remaining_lib_features
: &mut FxIndexMap
<&Symbol
, Span
>,
990 remaining_implications
: &mut FxHashMap
<Symbol
, Symbol
>,
991 defined_features
: &[(Symbol
, Option
<Symbol
>)],
992 all_implications
: &FxHashMap
<Symbol
, Symbol
>,
994 for (feature
, since
) in defined_features
{
995 if let Some(since
) = since
&& let Some(span
) = remaining_lib_features
.get(&feature
) {
996 // Warn if the user has enabled an already-stable lib feature.
997 if let Some(implies
) = all_implications
.get(&feature
) {
998 unnecessary_partially_stable_feature_lint(tcx
, *span
, *feature
, *implies
, *since
);
1000 unnecessary_stable_feature_lint(tcx
, *span
, *feature
, *since
);
1004 remaining_lib_features
.remove(feature
);
1006 // `feature` is the feature doing the implying, but `implied_by` is the feature with
1007 // the attribute that establishes this relationship. `implied_by` is guaranteed to be a
1008 // feature defined in the local crate because `remaining_implications` is only the
1009 // implications from this crate.
1010 remaining_implications
.remove(feature
);
1012 if remaining_lib_features
.is_empty() && remaining_implications
.is_empty() {
1018 // All local crate implications need to have the feature that implies it confirmed to exist.
1019 let mut remaining_implications
=
1020 tcx
.stability_implications(rustc_hir
::def_id
::LOCAL_CRATE
).clone();
1022 // We always collect the lib features declared in the current crate, even if there are
1023 // no unknown features, because the collection also does feature attribute validation.
1024 let local_defined_features
= tcx
.lib_features(()).to_vec();
1025 if !remaining_lib_features
.is_empty() || !remaining_implications
.is_empty() {
1026 // Loading the implications of all crates is unavoidable to be able to emit the partial
1027 // stabilization diagnostic, but it can be avoided when there are no
1028 // `remaining_lib_features`.
1029 let mut all_implications
= remaining_implications
.clone();
1030 for &cnum
in tcx
.crates(()) {
1031 all_implications
.extend(tcx
.stability_implications(cnum
));
1036 &mut remaining_lib_features
,
1037 &mut remaining_implications
,
1038 local_defined_features
.as_slice(),
1042 for &cnum
in tcx
.crates(()) {
1043 if remaining_lib_features
.is_empty() && remaining_implications
.is_empty() {
1048 &mut remaining_lib_features
,
1049 &mut remaining_implications
,
1050 tcx
.defined_lib_features(cnum
).to_vec().as_slice(),
1056 for (feature
, span
) in remaining_lib_features
{
1057 tcx
.sess
.emit_err(UnknownFeature { span, feature: *feature }
);
1060 for (implied_by
, feature
) in remaining_implications
{
1061 let local_defined_features
= tcx
.lib_features(());
1062 let span
= *local_defined_features
1065 .map(|(_
, span
)| span
)
1066 .or_else(|| local_defined_features
.unstable
.get(&feature
))
1067 .expect("feature that implied another does not exist");
1068 tcx
.sess
.emit_err(ImpliedFeatureNotExist { span, feature, implied_by }
);
1071 // FIXME(#44232): the `used_features` table no longer exists, so we
1072 // don't lint about unused features. We should re-enable this one day!
1075 fn unnecessary_partially_stable_feature_lint(
1082 tcx
.struct_span_lint_hir(
1083 lint
::builtin
::STABLE_FEATURES
,
1087 "the feature `{feature}` has been partially stabilized since {since} and is succeeded \
1088 by the feature `{implies}`"
1091 lint
.span_suggestion(
1094 "if you are using features which are still unstable, change to using `{implies}`"
1097 Applicability
::MaybeIncorrect
,
1100 tcx
.sess
.source_map().span_extend_to_line(span
),
1101 "if you are using features which are now stable, remove this line",
1103 Applicability
::MaybeIncorrect
,
1109 fn unnecessary_stable_feature_lint(
1115 if since
.as_str() == VERSION_PLACEHOLDER
{
1116 since
= rust_version_symbol();
1118 tcx
.struct_span_lint_hir(lint
::builtin
::STABLE_FEATURES
, hir
::CRATE_HIR_ID
, span
, format
!("the feature `{feature}` has been stable since {since} and no longer requires an attribute to enable"), |lint
| {