]>
Commit | Line | Data |
---|---|---|
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 | 4 | use crate::errors; |
f2b60f7d FG |
5 | use rustc_attr::{ |
6 | self as attr, rust_version_symbol, ConstStability, Stability, StabilityLevel, Unstable, | |
7 | UnstableReason, VERSION_PLACEHOLDER, | |
8 | }; | |
064997fb | 9 | use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; |
2b03887a | 10 | use rustc_errors::Applicability; |
dfeec247 XL |
11 | use rustc_hir as hir; |
12 | use rustc_hir::def::{DefKind, Res}; | |
04454e1e | 13 | use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; |
c295e0f8 | 14 | use rustc_hir::hir_id::CRATE_HIR_ID; |
5099ac24 | 15 | use rustc_hir::intravisit::{self, Visitor}; |
f2b60f7d | 16 | use rustc_hir::{FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant}; |
5099ac24 | 17 | use rustc_middle::hir::nested_filter; |
2b03887a | 18 | use rustc_middle::middle::privacy::EffectiveVisibilities; |
923072b8 | 19 | use rustc_middle::middle::stability::{AllowUnstable, DeprecationEntry, Index}; |
064997fb | 20 | use rustc_middle::ty::{query::Providers, TyCtxt}; |
ba9703b0 | 21 | use rustc_session::lint; |
29967ef6 | 22 | use rustc_session::lint::builtin::{INEFFECTIVE_UNSTABLE_TRAIT_IMPL, USELESS_DEPRECATED}; |
dfeec247 | 23 | use rustc_span::symbol::{sym, Symbol}; |
064997fb | 24 | use rustc_span::Span; |
136023e0 | 25 | use rustc_target::spec::abi::Abi; |
dfeec247 XL |
26 | |
27 | use std::cmp::Ordering; | |
cdc7bbd5 | 28 | use std::iter; |
dfeec247 XL |
29 | use std::mem::replace; |
30 | use std::num::NonZeroU32; | |
31 | ||
32 | #[derive(PartialEq)] | |
33 | enum 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)] | |
51 | enum InheritDeprecation { | |
52 | Yes, | |
53 | No, | |
54 | } | |
55 | ||
56 | impl 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. | |
66 | enum InheritConstStability { | |
67 | Yes, | |
68 | No, | |
69 | } | |
70 | ||
71 | impl InheritConstStability { | |
72 | fn yes(&self) -> bool { | |
73 | matches!(self, InheritConstStability::Yes) | |
74 | } | |
75 | } | |
76 | ||
6a06907d XL |
77 | enum InheritStability { |
78 | Yes, | |
79 | No, | |
80 | } | |
81 | ||
82 | impl 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 |
89 | struct 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 | ||
98 | impl<'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 | ||
337 | impl<'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 | 525 | struct MissingStabilityAnnotations<'tcx> { |
dfeec247 | 526 | tcx: TyCtxt<'tcx>, |
2b03887a | 527 | effective_visibilities: &'tcx EffectiveVisibilities, |
dfeec247 XL |
528 | } |
529 | ||
f035d41b | 530 | impl<'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 | 571 | impl<'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 | 633 | fn 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 | 687 | fn 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 | 691 | pub(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 | ||
704 | struct Checker<'tcx> { | |
705 | tcx: TyCtxt<'tcx>, | |
706 | } | |
707 | ||
a2a8927a | 708 | impl<'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 | 863 | fn 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 |
885 | struct CheckTraitImplStable<'tcx> { |
886 | tcx: TyCtxt<'tcx>, | |
887 | fully_stable: bool, | |
888 | } | |
889 | ||
a2a8927a | 890 | impl<'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. | |
937 | pub 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 |
1091 | fn 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 |
1125 | fn 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 | } |