]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_passes/src/stability.rs
New upstream version 1.70.0+dfsg1
[rustc.git] / compiler / rustc_passes / src / stability.rs
CommitLineData
dfeec247
XL
1//! A pass that annotates every item and method with its stability level,
2//! propagating default levels lexically from parent to children ast nodes.
3
9ffffee4 4use crate::errors;
f2b60f7d
FG
5use rustc_attr::{
6 self as attr, rust_version_symbol, ConstStability, Stability, StabilityLevel, Unstable,
7 UnstableReason, VERSION_PLACEHOLDER,
8};
064997fb 9use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
2b03887a 10use rustc_errors::Applicability;
dfeec247
XL
11use rustc_hir as hir;
12use rustc_hir::def::{DefKind, Res};
04454e1e 13use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
c295e0f8 14use rustc_hir::hir_id::CRATE_HIR_ID;
5099ac24 15use rustc_hir::intravisit::{self, Visitor};
f2b60f7d 16use rustc_hir::{FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant};
5099ac24 17use rustc_middle::hir::nested_filter;
2b03887a 18use rustc_middle::middle::privacy::EffectiveVisibilities;
923072b8 19use rustc_middle::middle::stability::{AllowUnstable, DeprecationEntry, Index};
064997fb 20use rustc_middle::ty::{query::Providers, TyCtxt};
ba9703b0 21use rustc_session::lint;
29967ef6 22use rustc_session::lint::builtin::{INEFFECTIVE_UNSTABLE_TRAIT_IMPL, USELESS_DEPRECATED};
dfeec247 23use rustc_span::symbol::{sym, Symbol};
064997fb 24use rustc_span::Span;
136023e0 25use rustc_target::spec::abi::Abi;
dfeec247
XL
26
27use std::cmp::Ordering;
cdc7bbd5 28use std::iter;
dfeec247
XL
29use std::mem::replace;
30use std::num::NonZeroU32;
31
32#[derive(PartialEq)]
33enum AnnotationKind {
064997fb 34 /// Annotation is required if not inherited from unstable parents.
dfeec247 35 Required,
064997fb 36 /// Annotation is useless, reject it.
dfeec247 37 Prohibited,
064997fb 38 /// Deprecation annotation is useless, reject it. (Stability attribute is still required.)
29967ef6 39 DeprecationProhibited,
064997fb 40 /// Annotation itself is useless, but it can be propagated to children.
dfeec247
XL
41 Container,
42}
43
1b1a35ee
XL
44/// Whether to inherit deprecation flags for nested items. In most cases, we do want to inherit
45/// deprecation, because nested items rarely have individual deprecation attributes, and so
46/// should be treated as deprecated if their parent is. However, default generic parameters
47/// have separate deprecation attributes from their parents, so we do not wish to inherit
48/// deprecation in this case. For example, inheriting deprecation for `T` in `Foo<T>`
49/// would cause a duplicate warning arising from both `Foo` and `T` being deprecated.
50#[derive(Clone)]
51enum InheritDeprecation {
52 Yes,
53 No,
54}
55
56impl InheritDeprecation {
57 fn yes(&self) -> bool {
58 matches!(self, InheritDeprecation::Yes)
59 }
60}
61
5869c6ff
XL
62/// Whether to inherit const stability flags for nested items. In most cases, we do not want to
63/// inherit const stability: just because an enclosing `fn` is const-stable does not mean
64/// all `extern` imports declared in it should be const-stable! However, trait methods
65/// inherit const stability attributes from their parent and do not have their own.
66enum InheritConstStability {
67 Yes,
68 No,
69}
70
71impl InheritConstStability {
72 fn yes(&self) -> bool {
73 matches!(self, InheritConstStability::Yes)
74 }
75}
76
6a06907d
XL
77enum InheritStability {
78 Yes,
79 No,
80}
81
82impl InheritStability {
83 fn yes(&self) -> bool {
84 matches!(self, InheritStability::Yes)
85 }
86}
87
064997fb 88/// A private tree-walker for producing an `Index`.
dfeec247
XL
89struct Annotator<'a, 'tcx> {
90 tcx: TyCtxt<'tcx>,
5e7ed085
FG
91 index: &'a mut Index,
92 parent_stab: Option<Stability>,
93 parent_const_stab: Option<ConstStability>,
dfeec247
XL
94 parent_depr: Option<DeprecationEntry>,
95 in_trait_impl: bool,
96}
97
98impl<'a, 'tcx> Annotator<'a, 'tcx> {
064997fb
FG
99 /// Determine the stability for a node based on its attributes and inherited stability. The
100 /// stability is recorded in the index and used as the parent. If the node is a function,
101 /// `fn_sig` is its signature.
dfeec247
XL
102 fn annotate<F>(
103 &mut self,
94222f64 104 def_id: LocalDefId,
dfeec247 105 item_sp: Span,
136023e0 106 fn_sig: Option<&'tcx hir::FnSig<'tcx>>,
dfeec247 107 kind: AnnotationKind,
1b1a35ee 108 inherit_deprecation: InheritDeprecation,
5869c6ff 109 inherit_const_stability: InheritConstStability,
6a06907d 110 inherit_from_parent: InheritStability,
dfeec247
XL
111 visit_children: F,
112 ) where
113 F: FnOnce(&mut Self),
114 {
04454e1e 115 let attrs = self.tcx.hir().attrs(self.tcx.hir().local_def_id_to_hir_id(def_id));
94222f64 116 debug!("annotate(id = {:?}, attrs = {:?})", def_id, attrs);
74b04a01 117
5e7ed085 118 let depr = attr::find_deprecation(&self.tcx.sess, attrs);
3dfed10e 119 let mut is_deprecated = false;
29967ef6 120 if let Some((depr, span)) = &depr {
3dfed10e 121 is_deprecated = true;
74b04a01 122
9ffffee4 123 if matches!(kind, AnnotationKind::Prohibited | AnnotationKind::DeprecationProhibited) {
94222f64 124 let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
2b03887a
FG
125 self.tcx.emit_spanned_lint(
126 USELESS_DEPRECATED,
127 hir_id,
128 *span,
129 errors::DeprecatedAnnotationHasNoEffect { span: *span },
130 );
3dfed10e
XL
131 }
132
133 // `Deprecation` is just two pointers, no need to intern it
04454e1e 134 let depr_entry = DeprecationEntry::local(*depr, def_id);
94222f64 135 self.index.depr_map.insert(def_id, depr_entry);
04454e1e 136 } else if let Some(parent_depr) = self.parent_depr {
1b1a35ee
XL
137 if inherit_deprecation.yes() {
138 is_deprecated = true;
94222f64
XL
139 info!("tagging child {:?} as deprecated from parent", def_id);
140 self.index.depr_map.insert(def_id, parent_depr);
1b1a35ee 141 }
3dfed10e
XL
142 }
143
5e7ed085 144 if !self.tcx.features().staged_api {
9c376795 145 // Propagate unstability. This can happen even for non-staged-api crates in case
5e7ed085
FG
146 // -Zforce-unstable-if-unmarked is set.
147 if let Some(stab) = self.parent_stab {
923072b8 148 if inherit_deprecation.yes() && stab.is_unstable() {
5e7ed085
FG
149 self.index.stab_map.insert(def_id, stab);
150 }
3dfed10e 151 }
5e7ed085 152
3dfed10e 153 self.recurse_with_stability_attrs(
94222f64 154 depr.map(|(d, _)| DeprecationEntry::local(d, def_id)),
3dfed10e
XL
155 None,
156 None,
157 visit_children,
74b04a01 158 );
3dfed10e 159 return;
74b04a01
XL
160 }
161
353b0b11
FG
162 let stab = attr::find_stability(&self.tcx.sess, attrs, item_sp);
163 let const_stab = attr::find_const_stability(&self.tcx.sess, attrs, item_sp);
164 let body_stab = attr::find_body_stability(&self.tcx.sess, attrs);
136023e0 165 let mut const_span = None;
74b04a01 166
136023e0 167 let const_stab = const_stab.map(|(const_stab, const_span_node)| {
94222f64 168 self.index.const_stab_map.insert(def_id, const_stab);
136023e0 169 const_span = Some(const_span_node);
74b04a01
XL
170 const_stab
171 });
172
136023e0
XL
173 // If the current node is a function, has const stability attributes and if it doesn not have an intrinsic ABI,
174 // check if the function/method is const or the parent impl block is const
175 if let (Some(const_span), Some(fn_sig)) = (const_span, fn_sig) {
176 if fn_sig.header.abi != Abi::RustIntrinsic
177 && fn_sig.header.abi != Abi::PlatformIntrinsic
178 && !fn_sig.header.is_const()
179 {
180 if !self.in_trait_impl
94222f64 181 || (self.in_trait_impl && !self.tcx.is_const_fn_raw(def_id.to_def_id()))
136023e0 182 {
2b03887a
FG
183 self.tcx
184 .sess
9ffffee4 185 .emit_err(errors::MissingConstErr { fn_sig_span: fn_sig.span, const_span });
136023e0
XL
186 }
187 }
188 }
189
5869c6ff
XL
190 // `impl const Trait for Type` items forward their const stability to their
191 // immediate children.
74b04a01
XL
192 if const_stab.is_none() {
193 debug!("annotate: const_stab not found, parent = {:?}", self.parent_const_stab);
194 if let Some(parent) = self.parent_const_stab {
923072b8 195 if parent.is_const_unstable() {
94222f64 196 self.index.const_stab_map.insert(def_id, parent);
74b04a01 197 }
dfeec247 198 }
74b04a01
XL
199 }
200
29967ef6 201 if let Some((rustc_attr::Deprecation { is_since_rustc_version: true, .. }, span)) = &depr {
3dfed10e 202 if stab.is_none() {
9ffffee4 203 self.tcx.sess.emit_err(errors::DeprecatedAttribute { span: *span });
3dfed10e
XL
204 }
205 }
206
f2b60f7d
FG
207 if let Some((body_stab, _span)) = body_stab {
208 // FIXME: check that this item can have body stability
209
210 self.index.default_body_stab_map.insert(def_id, body_stab);
211 debug!(?self.index.default_body_stab_map);
212 }
213
6a06907d 214 let stab = stab.map(|(stab, span)| {
74b04a01
XL
215 // Error if prohibited, or can't inherit anything from a container.
216 if kind == AnnotationKind::Prohibited
3dfed10e 217 || (kind == AnnotationKind::Container && stab.level.is_stable() && is_deprecated)
74b04a01 218 {
9ffffee4 219 self.tcx.sess.emit_err(errors::UselessStability { span, item_sp });
dfeec247 220 }
dfeec247 221
74b04a01 222 debug!("annotate: found {:?}", stab);
74b04a01
XL
223
224 // Check if deprecated_since < stable_since. If it is,
225 // this is *almost surely* an accident.
064997fb 226 if let (&Some(dep_since), &attr::Stable { since: stab_since, .. }) =
29967ef6 227 (&depr.as_ref().and_then(|(d, _)| d.since), &stab.level)
74b04a01
XL
228 {
229 // Explicit version of iter::order::lt to handle parse errors properly
230 for (dep_v, stab_v) in
cdc7bbd5 231 iter::zip(dep_since.as_str().split('.'), stab_since.as_str().split('.'))
dfeec247 232 {
fc512014
XL
233 match stab_v.parse::<u64>() {
234 Err(_) => {
9ffffee4 235 self.tcx.sess.emit_err(errors::InvalidStability { span, item_sp });
fc512014
XL
236 break;
237 }
238 Ok(stab_vp) => match dep_v.parse::<u64>() {
239 Ok(dep_vp) => match dep_vp.cmp(&stab_vp) {
240 Ordering::Less => {
9ffffee4
FG
241 self.tcx.sess.emit_err(errors::CannotStabilizeDeprecated {
242 span,
243 item_sp,
244 });
fc512014
XL
245 break;
246 }
247 Ordering::Equal => continue,
248 Ordering::Greater => break,
249 },
250 Err(_) => {
251 if dep_v != "TBD" {
9ffffee4
FG
252 self.tcx.sess.emit_err(errors::InvalidDeprecationVersion {
253 span,
254 item_sp,
255 });
fc512014 256 }
74b04a01 257 break;
dfeec247 258 }
fc512014 259 },
dfeec247
XL
260 }
261 }
dfeec247
XL
262 }
263
2b03887a
FG
264 if let Stability { level: Unstable { implied_by: Some(implied_by), .. }, feature } =
265 stab
266 {
064997fb
FG
267 self.index.implications.insert(implied_by, feature);
268 }
269
353b0b11
FG
270 if let Some(ConstStability {
271 level: Unstable { implied_by: Some(implied_by), .. },
272 feature,
273 ..
274 }) = const_stab
275 {
276 self.index.implications.insert(implied_by, feature);
277 }
278
94222f64 279 self.index.stab_map.insert(def_id, stab);
74b04a01
XL
280 stab
281 });
282
283 if stab.is_none() {
284 debug!("annotate: stab not found, parent = {:?}", self.parent_stab);
dfeec247 285 if let Some(stab) = self.parent_stab {
923072b8 286 if inherit_deprecation.yes() && stab.is_unstable() || inherit_from_parent.yes() {
94222f64 287 self.index.stab_map.insert(def_id, stab);
dfeec247
XL
288 }
289 }
74b04a01 290 }
dfeec247 291
3dfed10e 292 self.recurse_with_stability_attrs(
94222f64 293 depr.map(|(d, _)| DeprecationEntry::local(d, def_id)),
3dfed10e 294 stab,
9ffffee4 295 inherit_const_stability.yes().then_some(const_stab).flatten(),
3dfed10e
XL
296 visit_children,
297 );
74b04a01
XL
298 }
299
300 fn recurse_with_stability_attrs(
301 &mut self,
3dfed10e 302 depr: Option<DeprecationEntry>,
5e7ed085
FG
303 stab: Option<Stability>,
304 const_stab: Option<ConstStability>,
74b04a01
XL
305 f: impl FnOnce(&mut Self),
306 ) {
307 // These will be `Some` if this item changes the corresponding stability attribute.
3dfed10e 308 let mut replaced_parent_depr = None;
74b04a01
XL
309 let mut replaced_parent_stab = None;
310 let mut replaced_parent_const_stab = None;
311
3dfed10e
XL
312 if let Some(depr) = depr {
313 replaced_parent_depr = Some(replace(&mut self.parent_depr, Some(depr)));
314 }
74b04a01
XL
315 if let Some(stab) = stab {
316 replaced_parent_stab = Some(replace(&mut self.parent_stab, Some(stab)));
317 }
318 if let Some(const_stab) = const_stab {
319 replaced_parent_const_stab =
320 Some(replace(&mut self.parent_const_stab, Some(const_stab)));
321 }
322
323 f(self);
324
3dfed10e
XL
325 if let Some(orig_parent_depr) = replaced_parent_depr {
326 self.parent_depr = orig_parent_depr;
327 }
74b04a01
XL
328 if let Some(orig_parent_stab) = replaced_parent_stab {
329 self.parent_stab = orig_parent_stab;
330 }
331 if let Some(orig_parent_const_stab) = replaced_parent_const_stab {
332 self.parent_const_stab = orig_parent_const_stab;
333 }
334 }
dfeec247
XL
335}
336
337impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
338 /// Because stability levels are scoped lexically, we want to walk
339 /// nested items in the context of the outer item, so enable
340 /// deep-walking.
5099ac24 341 type NestedFilter = nested_filter::All;
dfeec247 342
5099ac24
FG
343 fn nested_visit_map(&mut self) -> Self::Map {
344 self.tcx.hir()
dfeec247
XL
345 }
346
347 fn visit_item(&mut self, i: &'tcx Item<'tcx>) {
348 let orig_in_trait_impl = self.in_trait_impl;
349 let mut kind = AnnotationKind::Required;
5869c6ff 350 let mut const_stab_inherit = InheritConstStability::No;
136023e0
XL
351 let mut fn_sig = None;
352
dfeec247
XL
353 match i.kind {
354 // Inherent impls and foreign modules serve only as containers for other items,
355 // they don't have their own stability. They still can be annotated as unstable
5e7ed085 356 // and propagate this instability to children, but this annotation is completely
dfeec247 357 // optional. They inherit stability from their parents when unannotated.
5869c6ff
XL
358 hir::ItemKind::Impl(hir::Impl { of_trait: None, .. })
359 | hir::ItemKind::ForeignMod { .. } => {
dfeec247
XL
360 self.in_trait_impl = false;
361 kind = AnnotationKind::Container;
362 }
5869c6ff 363 hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) => {
dfeec247 364 self.in_trait_impl = true;
29967ef6 365 kind = AnnotationKind::DeprecationProhibited;
5869c6ff 366 const_stab_inherit = InheritConstStability::Yes;
dfeec247
XL
367 }
368 hir::ItemKind::Struct(ref sd, _) => {
487cf647 369 if let Some(ctor_def_id) = sd.ctor_def_id() {
1b1a35ee 370 self.annotate(
487cf647 371 ctor_def_id,
1b1a35ee 372 i.span,
136023e0 373 None,
1b1a35ee
XL
374 AnnotationKind::Required,
375 InheritDeprecation::Yes,
5869c6ff 376 InheritConstStability::No,
6a06907d 377 InheritStability::Yes,
1b1a35ee
XL
378 |_| {},
379 )
dfeec247
XL
380 }
381 }
136023e0
XL
382 hir::ItemKind::Fn(ref item_fn_sig, _, _) => {
383 fn_sig = Some(item_fn_sig);
384 }
dfeec247
XL
385 _ => {}
386 }
387
5869c6ff 388 self.annotate(
2b03887a 389 i.owner_id.def_id,
5869c6ff 390 i.span,
136023e0 391 fn_sig,
5869c6ff
XL
392 kind,
393 InheritDeprecation::Yes,
394 const_stab_inherit,
6a06907d 395 InheritStability::No,
5869c6ff
XL
396 |v| intravisit::walk_item(v, i),
397 );
dfeec247
XL
398 self.in_trait_impl = orig_in_trait_impl;
399 }
400
401 fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) {
136023e0
XL
402 let fn_sig = match ti.kind {
403 hir::TraitItemKind::Fn(ref fn_sig, _) => Some(fn_sig),
404 _ => None,
405 };
406
1b1a35ee 407 self.annotate(
2b03887a 408 ti.owner_id.def_id,
1b1a35ee 409 ti.span,
136023e0 410 fn_sig,
1b1a35ee
XL
411 AnnotationKind::Required,
412 InheritDeprecation::Yes,
5869c6ff 413 InheritConstStability::No,
6a06907d 414 InheritStability::No,
1b1a35ee
XL
415 |v| {
416 intravisit::walk_trait_item(v, ti);
417 },
418 );
dfeec247
XL
419 }
420
421 fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) {
422 let kind =
423 if self.in_trait_impl { AnnotationKind::Prohibited } else { AnnotationKind::Required };
136023e0
XL
424
425 let fn_sig = match ii.kind {
426 hir::ImplItemKind::Fn(ref fn_sig, _) => Some(fn_sig),
427 _ => None,
428 };
429
5869c6ff 430 self.annotate(
2b03887a 431 ii.owner_id.def_id,
5869c6ff 432 ii.span,
136023e0 433 fn_sig,
5869c6ff
XL
434 kind,
435 InheritDeprecation::Yes,
436 InheritConstStability::No,
6a06907d 437 InheritStability::No,
5869c6ff
XL
438 |v| {
439 intravisit::walk_impl_item(v, ii);
440 },
441 );
dfeec247
XL
442 }
443
f2b60f7d 444 fn visit_variant(&mut self, var: &'tcx Variant<'tcx>) {
1b1a35ee 445 self.annotate(
487cf647 446 var.def_id,
1b1a35ee 447 var.span,
136023e0 448 None,
1b1a35ee
XL
449 AnnotationKind::Required,
450 InheritDeprecation::Yes,
5869c6ff 451 InheritConstStability::No,
6a06907d 452 InheritStability::Yes,
1b1a35ee 453 |v| {
487cf647 454 if let Some(ctor_def_id) = var.data.ctor_def_id() {
1b1a35ee 455 v.annotate(
487cf647 456 ctor_def_id,
1b1a35ee 457 var.span,
136023e0 458 None,
1b1a35ee
XL
459 AnnotationKind::Required,
460 InheritDeprecation::Yes,
5869c6ff 461 InheritConstStability::No,
f2b60f7d 462 InheritStability::Yes,
1b1a35ee
XL
463 |_| {},
464 );
465 }
dfeec247 466
f2b60f7d 467 intravisit::walk_variant(v, var)
1b1a35ee
XL
468 },
469 )
dfeec247
XL
470 }
471
6a06907d 472 fn visit_field_def(&mut self, s: &'tcx FieldDef<'tcx>) {
1b1a35ee 473 self.annotate(
487cf647 474 s.def_id,
1b1a35ee 475 s.span,
136023e0 476 None,
1b1a35ee
XL
477 AnnotationKind::Required,
478 InheritDeprecation::Yes,
5869c6ff 479 InheritConstStability::No,
6a06907d 480 InheritStability::Yes,
1b1a35ee 481 |v| {
6a06907d 482 intravisit::walk_field_def(v, s);
1b1a35ee
XL
483 },
484 );
dfeec247
XL
485 }
486
487 fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) {
1b1a35ee 488 self.annotate(
2b03887a 489 i.owner_id.def_id,
1b1a35ee 490 i.span,
136023e0 491 None,
1b1a35ee
XL
492 AnnotationKind::Required,
493 InheritDeprecation::Yes,
5869c6ff 494 InheritConstStability::No,
6a06907d 495 InheritStability::No,
1b1a35ee
XL
496 |v| {
497 intravisit::walk_foreign_item(v, i);
498 },
499 );
dfeec247
XL
500 }
501
1b1a35ee
XL
502 fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) {
503 let kind = match &p.kind {
cdc7bbd5
XL
504 // Allow stability attributes on default generic arguments.
505 hir::GenericParamKind::Type { default: Some(_), .. }
506 | hir::GenericParamKind::Const { default: Some(_), .. } => AnnotationKind::Container,
1b1a35ee
XL
507 _ => AnnotationKind::Prohibited,
508 };
509
5869c6ff 510 self.annotate(
487cf647 511 p.def_id,
5869c6ff 512 p.span,
136023e0 513 None,
5869c6ff
XL
514 kind,
515 InheritDeprecation::No,
516 InheritConstStability::No,
6a06907d 517 InheritStability::No,
5869c6ff
XL
518 |v| {
519 intravisit::walk_generic_param(v, p);
520 },
521 );
dfeec247
XL
522 }
523}
524
f035d41b 525struct MissingStabilityAnnotations<'tcx> {
dfeec247 526 tcx: TyCtxt<'tcx>,
2b03887a 527 effective_visibilities: &'tcx EffectiveVisibilities,
dfeec247
XL
528}
529
f035d41b 530impl<'tcx> MissingStabilityAnnotations<'tcx> {
94222f64
XL
531 fn check_missing_stability(&self, def_id: LocalDefId, span: Span) {
532 let stab = self.tcx.stability().local_stability(def_id);
353b0b11 533 if !self.tcx.sess.is_test_crate()
2b03887a
FG
534 && stab.is_none()
535 && self.effective_visibilities.is_reachable(def_id)
536 {
9ffffee4
FG
537 let descr = self.tcx.def_descr(def_id.to_def_id());
538 self.tcx.sess.emit_err(errors::MissingStabilityAttr { span, descr });
dfeec247
XL
539 }
540 }
1b1a35ee 541
94222f64 542 fn check_missing_const_stability(&self, def_id: LocalDefId, span: Span) {
5099ac24
FG
543 if !self.tcx.features().staged_api {
544 return;
545 }
546
487cf647
FG
547 // if the const impl is derived using the `derive_const` attribute,
548 // then it would be "stable" at least for the impl.
549 // We gate usages of it using `feature(const_trait_impl)` anyways
550 // so there is no unstable leakage
9ffffee4 551 if self.tcx.is_automatically_derived(def_id.to_def_id()) {
487cf647
FG
552 return;
553 }
554
923072b8
FG
555 let is_const = self.tcx.is_const_fn(def_id.to_def_id())
556 || self.tcx.is_const_trait_impl_raw(def_id.to_def_id());
5099ac24
FG
557 let is_stable = self
558 .tcx
559 .lookup_stability(def_id)
560 .map_or(false, |stability| stability.level.is_stable());
561 let missing_const_stability_attribute = self.tcx.lookup_const_stability(def_id).is_none();
2b03887a 562 let is_reachable = self.effective_visibilities.is_reachable(def_id);
5099ac24
FG
563
564 if is_const && is_stable && missing_const_stability_attribute && is_reachable {
9ffffee4
FG
565 let descr = self.tcx.def_descr(def_id.to_def_id());
566 self.tcx.sess.emit_err(errors::MissingConstStabAttr { span, descr });
1b1a35ee
XL
567 }
568 }
dfeec247
XL
569}
570
f035d41b 571impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> {
5099ac24 572 type NestedFilter = nested_filter::OnlyBodies;
dfeec247 573
5099ac24
FG
574 fn nested_visit_map(&mut self) -> Self::Map {
575 self.tcx.hir()
dfeec247
XL
576 }
577
578 fn visit_item(&mut self, i: &'tcx Item<'tcx>) {
1b1a35ee
XL
579 // Inherent impls and foreign modules serve only as containers for other items,
580 // they don't have their own stability. They still can be annotated as unstable
5e7ed085 581 // and propagate this instability to children, but this annotation is completely
1b1a35ee
XL
582 // optional. They inherit stability from their parents when unannotated.
583 if !matches!(
584 i.kind,
5869c6ff
XL
585 hir::ItemKind::Impl(hir::Impl { of_trait: None, .. })
586 | hir::ItemKind::ForeignMod { .. }
1b1a35ee 587 ) {
2b03887a 588 self.check_missing_stability(i.owner_id.def_id, i.span);
1b1a35ee 589 }
dfeec247 590
5099ac24 591 // Ensure stable `const fn` have a const stability attribute.
2b03887a 592 self.check_missing_const_stability(i.owner_id.def_id, i.span);
dfeec247
XL
593
594 intravisit::walk_item(self, i)
595 }
596
597 fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) {
2b03887a 598 self.check_missing_stability(ti.owner_id.def_id, ti.span);
dfeec247
XL
599 intravisit::walk_trait_item(self, ti);
600 }
601
602 fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) {
5099ac24 603 let impl_def_id = self.tcx.hir().get_parent_item(ii.hir_id());
dfeec247 604 if self.tcx.impl_trait_ref(impl_def_id).is_none() {
2b03887a
FG
605 self.check_missing_stability(ii.owner_id.def_id, ii.span);
606 self.check_missing_const_stability(ii.owner_id.def_id, ii.span);
dfeec247
XL
607 }
608 intravisit::walk_impl_item(self, ii);
609 }
610
f2b60f7d 611 fn visit_variant(&mut self, var: &'tcx Variant<'tcx>) {
487cf647
FG
612 self.check_missing_stability(var.def_id, var.span);
613 if let Some(ctor_def_id) = var.data.ctor_def_id() {
614 self.check_missing_stability(ctor_def_id, var.span);
f2b60f7d
FG
615 }
616 intravisit::walk_variant(self, var);
dfeec247
XL
617 }
618
6a06907d 619 fn visit_field_def(&mut self, s: &'tcx FieldDef<'tcx>) {
487cf647 620 self.check_missing_stability(s.def_id, s.span);
6a06907d 621 intravisit::walk_field_def(self, s);
dfeec247
XL
622 }
623
624 fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) {
2b03887a 625 self.check_missing_stability(i.owner_id.def_id, i.span);
dfeec247
XL
626 intravisit::walk_foreign_item(self, i);
627 }
1b1a35ee
XL
628 // Note that we don't need to `check_missing_stability` for default generic parameters,
629 // as we assume that any default generic parameters without attributes are automatically
630 // stable (assuming they have not inherited instability from their parent).
dfeec247
XL
631}
632
5e7ed085 633fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index {
dfeec247 634 let mut index = Index {
dfeec247
XL
635 stab_map: Default::default(),
636 const_stab_map: Default::default(),
f2b60f7d 637 default_body_stab_map: Default::default(),
dfeec247 638 depr_map: Default::default(),
064997fb 639 implications: Default::default(),
dfeec247
XL
640 };
641
dfeec247 642 {
dfeec247
XL
643 let mut annotator = Annotator {
644 tcx,
645 index: &mut index,
646 parent_stab: None,
74b04a01 647 parent_const_stab: None,
dfeec247
XL
648 parent_depr: None,
649 in_trait_impl: false,
650 };
651
652 // If the `-Z force-unstable-if-unmarked` flag is passed then we provide
653 // a parent stability annotation which indicates that this is private
654 // with the `rustc_private` feature. This is intended for use when
ba9703b0 655 // compiling `librustc_*` crates themselves so we can leverage crates.io
dfeec247
XL
656 // while maintaining the invariant that all sysroot crates are unstable
657 // by default and are unable to be used.
064997fb 658 if tcx.sess.opts.unstable_opts.force_unstable_if_unmarked {
5e7ed085 659 let stability = Stability {
dfeec247 660 level: attr::StabilityLevel::Unstable {
064997fb 661 reason: UnstableReason::Default,
dfeec247
XL
662 issue: NonZeroU32::new(27812),
663 is_soft: false,
064997fb 664 implied_by: None,
dfeec247
XL
665 },
666 feature: sym::rustc_private,
5e7ed085 667 };
dfeec247
XL
668 annotator.parent_stab = Some(stability);
669 }
670
671 annotator.annotate(
94222f64 672 CRATE_DEF_ID,
c295e0f8 673 tcx.hir().span(CRATE_HIR_ID),
136023e0 674 None,
dfeec247 675 AnnotationKind::Required,
1b1a35ee 676 InheritDeprecation::Yes,
5869c6ff 677 InheritConstStability::No,
6a06907d 678 InheritStability::No,
c295e0f8 679 |v| tcx.hir().walk_toplevel_module(v),
dfeec247
XL
680 );
681 }
ba9703b0 682 index
dfeec247
XL
683}
684
685/// Cross-references the feature names of unstable APIs with enabled
686/// features and possibly prints errors.
f035d41b 687fn check_mod_unstable_api_usage(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
064997fb 688 tcx.hir().visit_item_likes_in_module(module_def_id, &mut Checker { tcx });
dfeec247
XL
689}
690
f035d41b 691pub(crate) fn provide(providers: &mut Providers) {
5e7ed085
FG
692 *providers = Providers {
693 check_mod_unstable_api_usage,
694 stability_index,
064997fb 695 stability_implications: |tcx, _| tcx.stability().implications.clone(),
353b0b11
FG
696 lookup_stability: |tcx, id| tcx.stability().local_stability(id),
697 lookup_const_stability: |tcx, id| tcx.stability().local_const_stability(id),
698 lookup_default_body_stability: |tcx, id| tcx.stability().local_default_body_stability(id),
699 lookup_deprecation_entry: |tcx, id| tcx.stability().local_deprecation_entry(id),
5e7ed085
FG
700 ..*providers
701 };
dfeec247
XL
702}
703
704struct Checker<'tcx> {
705 tcx: TyCtxt<'tcx>,
706}
707
a2a8927a 708impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
5099ac24 709 type NestedFilter = nested_filter::OnlyBodies;
dfeec247
XL
710
711 /// Because stability levels are scoped lexically, we want to walk
712 /// nested items in the context of the outer item, so enable
713 /// deep-walking.
5099ac24
FG
714 fn nested_visit_map(&mut self) -> Self::Map {
715 self.tcx.hir()
dfeec247
XL
716 }
717
718 fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
719 match item.kind {
720 hir::ItemKind::ExternCrate(_) => {
721 // compiler-generated `extern crate` items have a dummy span.
3dfed10e 722 // `std` is still checked for the `restricted-std` feature.
04454e1e 723 if item.span.is_dummy() && item.ident.name != sym::std {
dfeec247
XL
724 return;
725 }
726
2b03887a 727 let Some(cnum) = self.tcx.extern_mod_stmt_cnum(item.owner_id.def_id) else {
5e7ed085 728 return;
dfeec247 729 };
04454e1e 730 let def_id = cnum.as_def_id();
17df50a5 731 self.tcx.check_stability(def_id, Some(item.hir_id()), item.span, None);
dfeec247
XL
732 }
733
734 // For implementations of traits, check the stability of each item
735 // individually as it's possible to have a stable trait with unstable
736 // items.
923072b8
FG
737 hir::ItemKind::Impl(hir::Impl {
738 of_trait: Some(ref t),
739 self_ty,
740 items,
741 constness,
742 ..
743 }) => {
744 let features = self.tcx.features();
745 if features.staged_api {
746 let attrs = self.tcx.hir().attrs(item.hir_id());
353b0b11
FG
747 let stab = attr::find_stability(&self.tcx.sess, attrs, item.span);
748 let const_stab = attr::find_const_stability(&self.tcx.sess, attrs, item.span);
923072b8 749
1b1a35ee
XL
750 // If this impl block has an #[unstable] attribute, give an
751 // error if all involved types and traits are stable, because
752 // it will have no effect.
753 // See: https://github.com/rust-lang/rust/issues/55436
923072b8 754 if let Some((Stability { level: attr::Unstable { .. }, .. }, span)) = stab {
1b1a35ee
XL
755 let mut c = CheckTraitImplStable { tcx: self.tcx, fully_stable: true };
756 c.visit_ty(self_ty);
757 c.visit_trait_ref(t);
9ffffee4
FG
758
759 // do not lint when the trait isn't resolved, since resolution error should
760 // be fixed first
761 if t.path.res != Res::Err && c.fully_stable {
1b1a35ee
XL
762 self.tcx.struct_span_lint_hir(
763 INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
6a06907d 764 item.hir_id(),
1b1a35ee 765 span,
2b03887a
FG
766 "an `#[unstable]` annotation here has no effect",
767 |lint| lint.note("see issue #55436 <https://github.com/rust-lang/rust/issues/55436> for more information")
1b1a35ee
XL
768 );
769 }
770 }
923072b8
FG
771
772 // `#![feature(const_trait_impl)]` is unstable, so any impl declared stable
773 // needs to have an error emitted.
774 if features.const_trait_impl
775 && *constness == hir::Constness::Const
776 && const_stab.map_or(false, |(stab, _)| stab.is_const_stable())
777 {
9ffffee4 778 self.tcx.sess.emit_err(errors::TraitImplConstStable { span: item.span });
923072b8 779 }
1b1a35ee
XL
780 }
781
04454e1e 782 for impl_item_ref in *items {
2b03887a 783 let impl_item = self.tcx.associated_item(impl_item_ref.id.owner_id);
5099ac24
FG
784
785 if let Some(def_id) = impl_item.trait_item_def_id {
786 // Pass `None` to skip deprecation warnings.
787 self.tcx.check_stability(def_id, None, impl_item_ref.span, None);
dfeec247
XL
788 }
789 }
790 }
791
dfeec247
XL
792 _ => (/* pass */),
793 }
794 intravisit::walk_item(self, item);
795 }
796
487cf647 797 fn visit_path(&mut self, path: &hir::Path<'tcx>, id: hir::HirId) {
dfeec247 798 if let Some(def_id) = path.res.opt_def_id() {
136023e0 799 let method_span = path.segments.last().map(|s| s.ident.span);
064997fb 800 let item_is_allowed = self.tcx.check_stability_allow_unstable(
923072b8
FG
801 def_id,
802 Some(id),
803 path.span,
804 method_span,
805 if is_unstable_reexport(self.tcx, id) {
806 AllowUnstable::Yes
807 } else {
808 AllowUnstable::No
809 },
064997fb
FG
810 );
811
812 let is_allowed_through_unstable_modules = |def_id| {
813 self.tcx
814 .lookup_stability(def_id)
815 .map(|stab| match stab.level {
816 StabilityLevel::Stable { allowed_through_unstable_modules, .. } => {
817 allowed_through_unstable_modules
818 }
819 _ => false,
820 })
821 .unwrap_or(false)
822 };
823
824 if item_is_allowed && !is_allowed_through_unstable_modules(def_id) {
825 // Check parent modules stability as well if the item the path refers to is itself
826 // stable. We only emit warnings for unstable path segments if the item is stable
827 // or allowed because stability is often inherited, so the most common case is that
828 // both the segments and the item are unstable behind the same feature flag.
829 //
830 // We check here rather than in `visit_path_segment` to prevent visiting the last
831 // path segment twice
832 //
833 // We include special cases via #[rustc_allowed_through_unstable_modules] for items
834 // that were accidentally stabilized through unstable paths before this check was
835 // added, such as `core::intrinsics::transmute`
836 let parents = path.segments.iter().rev().skip(1);
837 for path_segment in parents {
f2b60f7d 838 if let Some(def_id) = path_segment.res.opt_def_id() {
064997fb
FG
839 // use `None` for id to prevent deprecation check
840 self.tcx.check_stability_allow_unstable(
841 def_id,
842 None,
843 path.span,
844 None,
845 if is_unstable_reexport(self.tcx, id) {
846 AllowUnstable::Yes
847 } else {
848 AllowUnstable::No
849 },
850 );
851 }
852 }
853 }
dfeec247 854 }
064997fb 855
dfeec247
XL
856 intravisit::walk_path(self, path)
857 }
858}
859
923072b8
FG
860/// Check whether a path is a `use` item that has been marked as unstable.
861///
862/// See issue #94972 for details on why this is a special case
9c376795 863fn is_unstable_reexport(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
923072b8 864 // Get the LocalDefId so we can lookup the item to check the kind.
9ffffee4
FG
865 let Some(owner) = id.as_owner() else { return false; };
866 let def_id = owner.def_id;
923072b8
FG
867
868 let Some(stab) = tcx.stability().local_stability(def_id) else {
869 return false;
870 };
871
872 if stab.level.is_stable() {
873 // The re-export is not marked as unstable, don't override
874 return false;
875 }
876
877 // If this is a path that isn't a use, we don't need to do anything special
2b03887a 878 if !matches!(tcx.hir().expect_item(def_id).kind, ItemKind::Use(..)) {
923072b8
FG
879 return false;
880 }
881
882 true
883}
884
1b1a35ee
XL
885struct CheckTraitImplStable<'tcx> {
886 tcx: TyCtxt<'tcx>,
887 fully_stable: bool,
888}
889
a2a8927a 890impl<'tcx> Visitor<'tcx> for CheckTraitImplStable<'tcx> {
487cf647 891 fn visit_path(&mut self, path: &hir::Path<'tcx>, _id: hir::HirId) {
1b1a35ee
XL
892 if let Some(def_id) = path.res.opt_def_id() {
893 if let Some(stab) = self.tcx.lookup_stability(def_id) {
894 self.fully_stable &= stab.level.is_stable();
895 }
896 }
897 intravisit::walk_path(self, path)
898 }
899
900 fn visit_trait_ref(&mut self, t: &'tcx TraitRef<'tcx>) {
901 if let Res::Def(DefKind::Trait, trait_did) = t.path.res {
902 if let Some(stab) = self.tcx.lookup_stability(trait_did) {
903 self.fully_stable &= stab.level.is_stable();
904 }
905 }
906 intravisit::walk_trait_ref(self, t)
907 }
908
909 fn visit_ty(&mut self, t: &'tcx Ty<'tcx>) {
910 if let TyKind::Never = t.kind {
911 self.fully_stable = false;
912 }
2b03887a
FG
913 if let TyKind::BareFn(f) = t.kind {
914 if rustc_target::spec::abi::is_stable(f.abi.name()).is_err() {
915 self.fully_stable = false;
916 }
917 }
1b1a35ee
XL
918 intravisit::walk_ty(self, t)
919 }
2b03887a
FG
920
921 fn visit_fn_decl(&mut self, fd: &'tcx hir::FnDecl<'tcx>) {
922 for ty in fd.inputs {
923 self.visit_ty(ty)
924 }
925 if let hir::FnRetTy::Return(output_ty) = fd.output {
926 match output_ty.kind {
927 TyKind::Never => {} // `-> !` is stable
928 _ => self.visit_ty(output_ty),
929 }
930 }
931 }
1b1a35ee
XL
932}
933
dfeec247
XL
934/// Given the list of enabled features that were not language features (i.e., that
935/// were expected to be library features), and the list of features used from
936/// libraries, identify activated features that don't exist and error about them.
937pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
5e7ed085 938 let is_staged_api =
064997fb 939 tcx.sess.opts.unstable_opts.force_unstable_if_unmarked || tcx.features().staged_api;
5e7ed085 940 if is_staged_api {
2b03887a
FG
941 let effective_visibilities = &tcx.effective_visibilities(());
942 let mut missing = MissingStabilityAnnotations { tcx, effective_visibilities };
c295e0f8
XL
943 missing.check_missing_stability(CRATE_DEF_ID, tcx.hir().span(CRATE_HIR_ID));
944 tcx.hir().walk_toplevel_module(&mut missing);
064997fb 945 tcx.hir().visit_all_item_likes_in_crate(&mut missing);
dfeec247
XL
946 }
947
948 let declared_lang_features = &tcx.features().declared_lang_features;
949 let mut lang_features = FxHashSet::default();
950 for &(feature, span, since) in declared_lang_features {
951 if let Some(since) = since {
952 // Warn if the user has enabled an already-stable lang feature.
953 unnecessary_stable_feature_lint(tcx, span, feature, since);
954 }
955 if !lang_features.insert(feature) {
956 // Warn if the user enables a lang feature multiple times.
9ffffee4 957 tcx.sess.emit_err(errors::DuplicateFeatureErr { span, feature });
dfeec247
XL
958 }
959 }
960
961 let declared_lib_features = &tcx.features().declared_lib_features;
5e7ed085 962 let mut remaining_lib_features = FxIndexMap::default();
dfeec247 963 for (feature, span) in declared_lib_features {
c295e0f8 964 if !tcx.sess.opts.unstable_features.is_nightly_build() {
9ffffee4 965 tcx.sess.emit_err(errors::FeatureOnlyOnNightly {
2b03887a
FG
966 span: *span,
967 release_channel: env!("CFG_RELEASE_CHANNEL"),
968 });
c295e0f8 969 }
dfeec247
XL
970 if remaining_lib_features.contains_key(&feature) {
971 // Warn if the user enables a lib feature multiple times.
9ffffee4 972 tcx.sess.emit_err(errors::DuplicateFeatureErr { span: *span, feature: *feature });
dfeec247 973 }
ba9703b0 974 remaining_lib_features.insert(feature, *span);
dfeec247
XL
975 }
976 // `stdbuild` has special handling for `libc`, so we need to
977 // recognise the feature when building std.
978 // Likewise, libtest is handled specially, so `test` isn't
979 // available as we'd like it to be.
980 // FIXME: only remove `libc` when `stdbuild` is active.
981 // FIXME: remove special casing for `test`.
3dfed10e 982 remaining_lib_features.remove(&sym::libc);
dfeec247
XL
983 remaining_lib_features.remove(&sym::test);
984
f2b60f7d
FG
985 /// For each feature in `defined_features`..
986 ///
987 /// - If it is in `remaining_lib_features` (those features with `#![feature(..)]` attributes in
988 /// the current crate), check if it is stable (or partially stable) and thus an unnecessary
989 /// attribute.
990 /// - If it is in `remaining_implications` (a feature that is referenced by an `implied_by`
991 /// from the current crate), then remove it from the remaining implications.
992 ///
993 /// Once this function has been invoked for every feature (local crate and all extern crates),
994 /// then..
995 ///
996 /// - If features remain in `remaining_lib_features`, then the user has enabled a feature that
997 /// does not exist.
998 /// - If features remain in `remaining_implications`, the `implied_by` refers to a feature that
999 /// does not exist.
1000 ///
1001 /// By structuring the code in this way: checking the features defined from each crate one at a
1002 /// time, less loading from metadata is performed and thus compiler performance is improved.
1003 fn check_features<'tcx>(
1004 tcx: TyCtxt<'tcx>,
1005 remaining_lib_features: &mut FxIndexMap<&Symbol, Span>,
1006 remaining_implications: &mut FxHashMap<Symbol, Symbol>,
1007 defined_features: &[(Symbol, Option<Symbol>)],
1008 all_implications: &FxHashMap<Symbol, Symbol>,
1009 ) {
1010 for (feature, since) in defined_features {
064997fb
FG
1011 if let Some(since) = since && let Some(span) = remaining_lib_features.get(&feature) {
1012 // Warn if the user has enabled an already-stable lib feature.
f2b60f7d 1013 if let Some(implies) = all_implications.get(&feature) {
064997fb
FG
1014 unnecessary_partially_stable_feature_lint(tcx, *span, *feature, *implies, *since);
1015 } else {
1016 unnecessary_stable_feature_lint(tcx, *span, *feature, *since);
1017 }
f2b60f7d
FG
1018
1019 }
1020 remaining_lib_features.remove(feature);
1021
1022 // `feature` is the feature doing the implying, but `implied_by` is the feature with
1023 // the attribute that establishes this relationship. `implied_by` is guaranteed to be a
1024 // feature defined in the local crate because `remaining_implications` is only the
1025 // implications from this crate.
1026 remaining_implications.remove(feature);
1027
1028 if remaining_lib_features.is_empty() && remaining_implications.is_empty() {
1029 break;
064997fb 1030 }
f2b60f7d
FG
1031 }
1032 }
1033
1034 // All local crate implications need to have the feature that implies it confirmed to exist.
1035 let mut remaining_implications =
1036 tcx.stability_implications(rustc_hir::def_id::LOCAL_CRATE).clone();
1037
1038 // We always collect the lib features declared in the current crate, even if there are
1039 // no unknown features, because the collection also does feature attribute validation.
1040 let local_defined_features = tcx.lib_features(()).to_vec();
1041 if !remaining_lib_features.is_empty() || !remaining_implications.is_empty() {
1042 // Loading the implications of all crates is unavoidable to be able to emit the partial
1043 // stabilization diagnostic, but it can be avoided when there are no
1044 // `remaining_lib_features`.
1045 let mut all_implications = remaining_implications.clone();
1046 for &cnum in tcx.crates(()) {
1047 all_implications.extend(tcx.stability_implications(cnum));
1048 }
1049
1050 check_features(
1051 tcx,
1052 &mut remaining_lib_features,
1053 &mut remaining_implications,
1054 local_defined_features.as_slice(),
1055 &all_implications,
1056 );
1057
1058 for &cnum in tcx.crates(()) {
1059 if remaining_lib_features.is_empty() && remaining_implications.is_empty() {
dfeec247
XL
1060 break;
1061 }
f2b60f7d
FG
1062 check_features(
1063 tcx,
1064 &mut remaining_lib_features,
1065 &mut remaining_implications,
1066 tcx.defined_lib_features(cnum).to_vec().as_slice(),
1067 &all_implications,
1068 );
dfeec247
XL
1069 }
1070 }
1071
1072 for (feature, span) in remaining_lib_features {
9ffffee4 1073 tcx.sess.emit_err(errors::UnknownFeature { span, feature: *feature });
dfeec247
XL
1074 }
1075
f2b60f7d
FG
1076 for (implied_by, feature) in remaining_implications {
1077 let local_defined_features = tcx.lib_features(());
2b03887a 1078 let span = *local_defined_features
f2b60f7d
FG
1079 .stable
1080 .get(&feature)
1081 .map(|(_, span)| span)
1082 .or_else(|| local_defined_features.unstable.get(&feature))
1083 .expect("feature that implied another does not exist");
9ffffee4 1084 tcx.sess.emit_err(errors::ImpliedFeatureNotExist { span, feature, implied_by });
f2b60f7d
FG
1085 }
1086
dfeec247 1087 // FIXME(#44232): the `used_features` table no longer exists, so we
74b04a01 1088 // don't lint about unused features. We should re-enable this one day!
dfeec247
XL
1089}
1090
064997fb
FG
1091fn unnecessary_partially_stable_feature_lint(
1092 tcx: TyCtxt<'_>,
1093 span: Span,
1094 feature: Symbol,
1095 implies: Symbol,
1096 since: Symbol,
1097) {
2b03887a
FG
1098 tcx.struct_span_lint_hir(
1099 lint::builtin::STABLE_FEATURES,
1100 hir::CRATE_HIR_ID,
1101 span,
1102 format!(
064997fb
FG
1103 "the feature `{feature}` has been partially stabilized since {since} and is succeeded \
1104 by the feature `{implies}`"
2b03887a
FG
1105 ),
1106 |lint| {
1107 lint.span_suggestion(
1108 span,
1109 &format!(
064997fb
FG
1110 "if you are using features which are still unstable, change to using `{implies}`"
1111 ),
2b03887a
FG
1112 implies,
1113 Applicability::MaybeIncorrect,
1114 )
1115 .span_suggestion(
1116 tcx.sess.source_map().span_extend_to_line(span),
1117 "if you are using features which are now stable, remove this line",
1118 "",
1119 Applicability::MaybeIncorrect,
1120 )
1121 },
1122 );
064997fb
FG
1123}
1124
f2b60f7d
FG
1125fn unnecessary_stable_feature_lint(
1126 tcx: TyCtxt<'_>,
1127 span: Span,
1128 feature: Symbol,
1129 mut since: Symbol,
1130) {
1131 if since.as_str() == VERSION_PLACEHOLDER {
1132 since = rust_version_symbol();
1133 }
2b03887a
FG
1134 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| {
1135 lint
74b04a01 1136 });
dfeec247 1137}