]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
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 | ||
b039eaaf SL |
4 | pub use self::StabilityLevel::*; |
5 | ||
3c0e092e | 6 | use crate::ty::{self, DefIdTree, TyCtxt}; |
fc512014 | 7 | use rustc_ast::NodeId; |
3dfed10e | 8 | use rustc_attr::{self as attr, ConstStability, Deprecation, Stability}; |
5e7ed085 FG |
9 | use rustc_data_structures::fx::FxHashMap; |
10 | use rustc_errors::{Applicability, Diagnostic}; | |
dfeec247 | 11 | use rustc_feature::GateIssue; |
dfeec247 | 12 | use rustc_hir::def::DefKind; |
04454e1e | 13 | use rustc_hir::def_id::{DefId, LocalDefId}; |
923072b8 | 14 | use rustc_hir::{self as hir, HirId}; |
1b1a35ee | 15 | use rustc_middle::ty::print::with_no_trimmed_paths; |
74b04a01 | 16 | use rustc_session::lint::builtin::{DEPRECATED, DEPRECATED_IN_FUTURE, SOFT_UNSTABLE}; |
c295e0f8 | 17 | use rustc_session::lint::{BuiltinLintDiagnostics, Level, Lint, LintBuffer}; |
74b04a01 | 18 | use rustc_session::parse::feature_err_issue; |
5e7ed085 | 19 | use rustc_session::Session; |
dfeec247 | 20 | use rustc_span::symbol::{sym, Symbol}; |
5e7ed085 | 21 | use rustc_span::Span; |
60c5eb7d XL |
22 | use std::num::NonZeroU32; |
23 | ||
e74abb32 | 24 | #[derive(PartialEq, Clone, Copy, Debug)] |
b039eaaf SL |
25 | pub enum StabilityLevel { |
26 | Unstable, | |
27 | Stable, | |
28 | } | |
29 | ||
5bcae85e | 30 | /// An entry in the `depr_map`. |
923072b8 | 31 | #[derive(Copy, Clone, HashStable, Debug, Encodable, Decodable)] |
5bcae85e SL |
32 | pub struct DeprecationEntry { |
33 | /// The metadata of the attribute associated with this entry. | |
34 | pub attr: Deprecation, | |
9fa01778 | 35 | /// The `DefId` where the attr was originally attached. `None` for non-local |
5bcae85e | 36 | /// `DefId`'s. |
94222f64 | 37 | origin: Option<LocalDefId>, |
5bcae85e SL |
38 | } |
39 | ||
40 | impl DeprecationEntry { | |
94222f64 XL |
41 | pub fn local(attr: Deprecation, def_id: LocalDefId) -> DeprecationEntry { |
42 | DeprecationEntry { attr, origin: Some(def_id) } | |
5bcae85e SL |
43 | } |
44 | ||
ea8adc8c | 45 | pub fn external(attr: Deprecation) -> DeprecationEntry { |
dfeec247 | 46 | DeprecationEntry { attr, origin: None } |
5bcae85e SL |
47 | } |
48 | ||
49 | pub fn same_origin(&self, other: &DeprecationEntry) -> bool { | |
50 | match (self.origin, other.origin) { | |
51 | (Some(o1), Some(o2)) => o1 == o2, | |
dfeec247 | 52 | _ => false, |
5bcae85e SL |
53 | } |
54 | } | |
55 | } | |
56 | ||
1a4d82fc | 57 | /// A stability index, giving the stability level for items and methods. |
5869c6ff | 58 | #[derive(HashStable, Debug)] |
5e7ed085 | 59 | pub struct Index { |
62682a34 SL |
60 | /// This is mostly a cache, except the stabilities of local items |
61 | /// are filled by the annotator. | |
5e7ed085 FG |
62 | pub stab_map: FxHashMap<LocalDefId, Stability>, |
63 | pub const_stab_map: FxHashMap<LocalDefId, ConstStability>, | |
94222f64 | 64 | pub depr_map: FxHashMap<LocalDefId, DeprecationEntry>, |
476ff2be SL |
65 | } |
66 | ||
5e7ed085 FG |
67 | impl Index { |
68 | pub fn local_stability(&self, def_id: LocalDefId) -> Option<Stability> { | |
94222f64 | 69 | self.stab_map.get(&def_id).copied() |
85aaf69f SL |
70 | } |
71 | ||
5e7ed085 | 72 | pub fn local_const_stability(&self, def_id: LocalDefId) -> Option<ConstStability> { |
94222f64 | 73 | self.const_stab_map.get(&def_id).copied() |
60c5eb7d XL |
74 | } |
75 | ||
94222f64 XL |
76 | pub fn local_deprecation_entry(&self, def_id: LocalDefId) -> Option<DeprecationEntry> { |
77 | self.depr_map.get(&def_id).cloned() | |
85aaf69f SL |
78 | } |
79 | } | |
80 | ||
416331ca | 81 | pub fn report_unstable( |
e74abb32 XL |
82 | sess: &Session, |
83 | feature: Symbol, | |
84 | reason: Option<Symbol>, | |
60c5eb7d | 85 | issue: Option<NonZeroU32>, |
3c0e092e | 86 | suggestion: Option<(Span, String, String, Applicability)>, |
e74abb32 XL |
87 | is_soft: bool, |
88 | span: Span, | |
74b04a01 | 89 | soft_handler: impl FnOnce(&'static Lint, Span, &str), |
416331ca XL |
90 | ) { |
91 | let msg = match reason { | |
92 | Some(r) => format!("use of unstable library feature '{}': {}", feature, r), | |
dfeec247 | 93 | None => format!("use of unstable library feature '{}'", &feature), |
416331ca XL |
94 | }; |
95 | ||
5e7ed085 FG |
96 | if is_soft { |
97 | soft_handler(SOFT_UNSTABLE, span, &msg) | |
98 | } else { | |
99 | let mut err = | |
100 | feature_err_issue(&sess.parse_sess, feature, span, GateIssue::Library(issue), &msg); | |
101 | if let Some((inner_types, ref msg, sugg, applicability)) = suggestion { | |
102 | err.span_suggestion(inner_types, msg, sugg, applicability); | |
416331ca | 103 | } |
5e7ed085 | 104 | err.emit(); |
416331ca XL |
105 | } |
106 | } | |
107 | ||
9fa01778 | 108 | /// Checks whether an item marked with `deprecated(since="X")` is currently |
0731742a | 109 | /// deprecated (i.e., whether X is not greater than the current rustc version). |
c295e0f8 XL |
110 | pub fn deprecation_in_effect(depr: &Deprecation) -> bool { |
111 | let is_since_rustc_version = depr.is_since_rustc_version; | |
a2a8927a | 112 | let since = depr.since.as_ref().map(Symbol::as_str); |
c295e0f8 | 113 | |
83c7162d | 114 | fn parse_version(ver: &str) -> Vec<u32> { |
0731742a | 115 | // We ignore non-integer components of the version (e.g., "nightly"). |
83c7162d XL |
116 | ver.split(|c| c == '.' || c == '-').flat_map(|s| s.parse()).collect() |
117 | } | |
118 | ||
fc512014 | 119 | if !is_since_rustc_version { |
04454e1e | 120 | // The `since` field doesn't have semantic purpose without `#![staged_api]`. |
fc512014 | 121 | return true; |
83c7162d | 122 | } |
fc512014 XL |
123 | |
124 | if let Some(since) = since { | |
125 | if since == "TBD" { | |
126 | return false; | |
127 | } | |
128 | ||
129 | if let Some(rustc) = option_env!("CFG_RELEASE") { | |
130 | let since: Vec<u32> = parse_version(&since); | |
131 | let rustc: Vec<u32> = parse_version(rustc); | |
132 | // We simply treat invalid `since` attributes as relating to a previous | |
133 | // Rust version, thus always displaying the warning. | |
134 | if since.len() != 3 { | |
135 | return true; | |
136 | } | |
137 | return since <= rustc; | |
138 | } | |
139 | }; | |
140 | ||
141 | // Assume deprecation is in effect if "since" field is missing | |
142 | // or if we can't determine the current Rust version. | |
143 | true | |
83c7162d XL |
144 | } |
145 | ||
416331ca | 146 | pub fn deprecation_suggestion( |
5e7ed085 | 147 | diag: &mut Diagnostic, |
3dfed10e | 148 | kind: &str, |
dfeec247 XL |
149 | suggestion: Option<Symbol>, |
150 | span: Span, | |
416331ca XL |
151 | ) { |
152 | if let Some(suggestion) = suggestion { | |
153 | diag.span_suggestion( | |
154 | span, | |
3dfed10e | 155 | &format!("replace the use of the deprecated {}", kind), |
923072b8 | 156 | suggestion, |
416331ca XL |
157 | Applicability::MachineApplicable, |
158 | ); | |
159 | } | |
160 | } | |
161 | ||
c295e0f8 XL |
162 | fn deprecation_lint(is_in_effect: bool) -> &'static Lint { |
163 | if is_in_effect { DEPRECATED } else { DEPRECATED_IN_FUTURE } | |
164 | } | |
165 | ||
166 | fn deprecation_message( | |
167 | is_in_effect: bool, | |
168 | since: Option<Symbol>, | |
169 | note: Option<Symbol>, | |
170 | kind: &str, | |
171 | path: &str, | |
172 | ) -> String { | |
173 | let message = if is_in_effect { | |
174 | format!("use of deprecated {} `{}`", kind, path) | |
416331ca | 175 | } else { |
a2a8927a | 176 | let since = since.as_ref().map(Symbol::as_str); |
c295e0f8 | 177 | |
5099ac24 | 178 | if since == Some("TBD") { |
c295e0f8 XL |
179 | format!("use of {} `{}` that will be deprecated in a future Rust version", kind, path) |
180 | } else { | |
181 | format!( | |
182 | "use of {} `{}` that will be deprecated in future version {}", | |
183 | kind, | |
184 | path, | |
185 | since.unwrap() | |
186 | ) | |
187 | } | |
416331ca | 188 | }; |
c295e0f8 XL |
189 | |
190 | match note { | |
3dfed10e XL |
191 | Some(reason) => format!("{}: {}", message, reason), |
192 | None => message, | |
c295e0f8 XL |
193 | } |
194 | } | |
195 | ||
196 | pub fn deprecation_message_and_lint( | |
197 | depr: &Deprecation, | |
198 | kind: &str, | |
199 | path: &str, | |
200 | ) -> (String, &'static Lint) { | |
201 | let is_in_effect = deprecation_in_effect(depr); | |
202 | ( | |
203 | deprecation_message(is_in_effect, depr.since, depr.note, kind, path), | |
204 | deprecation_lint(is_in_effect), | |
205 | ) | |
416331ca XL |
206 | } |
207 | ||
a2a8927a | 208 | pub fn early_report_deprecation<'a>( |
dfeec247 | 209 | lint_buffer: &'a mut LintBuffer, |
416331ca XL |
210 | message: &str, |
211 | suggestion: Option<Symbol>, | |
212 | lint: &'static Lint, | |
213 | span: Span, | |
fc512014 | 214 | node_id: NodeId, |
416331ca | 215 | ) { |
dfeec247 | 216 | if span.in_derive_expansion() { |
416331ca XL |
217 | return; |
218 | } | |
219 | ||
220 | let diag = BuiltinLintDiagnostics::DeprecatedMacro(suggestion, span); | |
fc512014 | 221 | lint_buffer.buffer_lint_with_diagnostic(lint, node_id, span, message, diag); |
416331ca XL |
222 | } |
223 | ||
224 | fn late_report_deprecation( | |
225 | tcx: TyCtxt<'_>, | |
226 | message: &str, | |
227 | suggestion: Option<Symbol>, | |
228 | lint: &'static Lint, | |
229 | span: Span, | |
136023e0 | 230 | method_span: Option<Span>, |
416331ca | 231 | hir_id: HirId, |
3dfed10e | 232 | def_id: DefId, |
416331ca | 233 | ) { |
dfeec247 | 234 | if span.in_derive_expansion() { |
416331ca XL |
235 | return; |
236 | } | |
136023e0 XL |
237 | let method_span = method_span.unwrap_or(span); |
238 | tcx.struct_span_lint_hir(lint, hir_id, method_span, |lint| { | |
74b04a01 XL |
239 | let mut diag = lint.build(message); |
240 | if let hir::Node::Expr(_) = tcx.hir().get(hir_id) { | |
3dfed10e | 241 | let kind = tcx.def_kind(def_id).descr(def_id); |
136023e0 | 242 | deprecation_suggestion(&mut diag, kind, suggestion, method_span); |
74b04a01 | 243 | } |
5e7ed085 | 244 | diag.emit(); |
74b04a01 | 245 | }); |
416331ca XL |
246 | } |
247 | ||
0531ce1d XL |
248 | /// Result of `TyCtxt::eval_stability`. |
249 | pub enum EvalResult { | |
250 | /// We can use the item because it is stable or we provided the | |
251 | /// corresponding feature gate. | |
252 | Allow, | |
253 | /// We cannot use the item because it is unstable and we did not provide the | |
254 | /// corresponding feature gate. | |
3c0e092e XL |
255 | Deny { |
256 | feature: Symbol, | |
257 | reason: Option<Symbol>, | |
258 | issue: Option<NonZeroU32>, | |
259 | suggestion: Option<(Span, String, String, Applicability)>, | |
260 | is_soft: bool, | |
261 | }, | |
0531ce1d XL |
262 | /// The item does not have the `#[stable]` or `#[unstable]` marker assigned. |
263 | Unmarked, | |
264 | } | |
265 | ||
dfeec247 | 266 | // See issue #38412. |
29967ef6 XL |
267 | fn skip_stability_check_due_to_privacy(tcx: TyCtxt<'_>, def_id: DefId) -> bool { |
268 | if tcx.def_kind(def_id) == DefKind::TyParam { | |
269 | // Have no visibility, considered public for the purpose of this check. | |
270 | return false; | |
dfeec247 | 271 | } |
29967ef6 | 272 | match tcx.visibility(def_id) { |
dfeec247 XL |
273 | // Must check stability for `pub` items. |
274 | ty::Visibility::Public => false, | |
476ff2be | 275 | |
dfeec247 XL |
276 | // These are not visible outside crate; therefore |
277 | // stability markers are irrelevant, if even present. | |
278 | ty::Visibility::Restricted(..) | ty::Visibility::Invisible => true, | |
476ff2be | 279 | } |
dfeec247 | 280 | } |
476ff2be | 281 | |
3c0e092e XL |
282 | // See issue #83250. |
283 | fn suggestion_for_allocator_api( | |
284 | tcx: TyCtxt<'_>, | |
285 | def_id: DefId, | |
286 | span: Span, | |
287 | feature: Symbol, | |
288 | ) -> Option<(Span, String, String, Applicability)> { | |
289 | if feature == sym::allocator_api { | |
04454e1e | 290 | if let Some(trait_) = tcx.opt_parent(def_id) { |
3c0e092e XL |
291 | if tcx.is_diagnostic_item(sym::Vec, trait_) { |
292 | let sm = tcx.sess.parse_sess.source_map(); | |
293 | let inner_types = sm.span_extend_to_prev_char(span, '<', true); | |
294 | if let Ok(snippet) = sm.span_to_snippet(inner_types) { | |
295 | return Some(( | |
296 | inner_types, | |
297 | "consider wrapping the inner types in tuple".to_string(), | |
298 | format!("({})", snippet), | |
299 | Applicability::MaybeIncorrect, | |
300 | )); | |
301 | } | |
302 | } | |
303 | } | |
304 | } | |
305 | None | |
306 | } | |
307 | ||
923072b8 FG |
308 | /// An override option for eval_stability. |
309 | pub enum AllowUnstable { | |
310 | /// Don't emit an unstable error for the item | |
311 | Yes, | |
312 | /// Handle the item normally | |
313 | No, | |
314 | } | |
315 | ||
dfeec247 | 316 | impl<'tcx> TyCtxt<'tcx> { |
0531ce1d XL |
317 | /// Evaluates the stability of an item. |
318 | /// | |
319 | /// Returns `EvalResult::Allow` if the item is stable, or unstable but the corresponding | |
320 | /// `#![feature]` has been provided. Returns `EvalResult::Deny` which describes the offending | |
321 | /// unstable feature otherwise. | |
322 | /// | |
323 | /// If `id` is `Some(_)`, this function will also check if the item at `def_id` has been | |
324 | /// deprecated. If the item is indeed deprecated, we will emit a deprecation lint attached to | |
325 | /// `id`. | |
17df50a5 XL |
326 | pub fn eval_stability( |
327 | self, | |
328 | def_id: DefId, | |
329 | id: Option<HirId>, | |
330 | span: Span, | |
331 | method_span: Option<Span>, | |
923072b8 FG |
332 | ) -> EvalResult { |
333 | self.eval_stability_allow_unstable(def_id, id, span, method_span, AllowUnstable::No) | |
334 | } | |
335 | ||
336 | /// Evaluates the stability of an item. | |
337 | /// | |
338 | /// Returns `EvalResult::Allow` if the item is stable, or unstable but the corresponding | |
339 | /// `#![feature]` has been provided. Returns `EvalResult::Deny` which describes the offending | |
340 | /// unstable feature otherwise. | |
341 | /// | |
342 | /// If `id` is `Some(_)`, this function will also check if the item at `def_id` has been | |
343 | /// deprecated. If the item is indeed deprecated, we will emit a deprecation lint attached to | |
344 | /// `id`. | |
345 | /// | |
346 | /// Pass `AllowUnstable::Yes` to `allow_unstable` to force an unstable item to be allowed. Deprecation warnings will be emitted normally. | |
347 | pub fn eval_stability_allow_unstable( | |
348 | self, | |
349 | def_id: DefId, | |
350 | id: Option<HirId>, | |
351 | span: Span, | |
352 | method_span: Option<Span>, | |
353 | allow_unstable: AllowUnstable, | |
17df50a5 | 354 | ) -> EvalResult { |
476ff2be | 355 | // Deprecated attributes apply in-crate and cross-crate. |
0531ce1d XL |
356 | if let Some(id) = id { |
357 | if let Some(depr_entry) = self.lookup_deprecation_entry(def_id) { | |
5099ac24 | 358 | let parent_def_id = self.hir().get_parent_item(id); |
dfeec247 | 359 | let skip = self |
f9f354fc | 360 | .lookup_deprecation_entry(parent_def_id.to_def_id()) |
dfeec247 | 361 | .map_or(false, |parent_depr| parent_depr.same_origin(&depr_entry)); |
0731742a | 362 | |
3dfed10e XL |
363 | // #[deprecated] doesn't emit a notice if we're not on the |
364 | // topmost deprecation. For example, if a struct is deprecated, | |
365 | // the use of a field won't be linted. | |
366 | // | |
04454e1e | 367 | // With #![staged_api], we want to emit down the whole |
3dfed10e | 368 | // hierarchy. |
c295e0f8 XL |
369 | let depr_attr = &depr_entry.attr; |
370 | if !skip || depr_attr.is_since_rustc_version { | |
371 | // Calculating message for lint involves calling `self.def_path_str`. | |
372 | // Which by default to calculate visible path will invoke expensive `visible_parent_map` query. | |
373 | // So we skip message calculation altogether, if lint is allowed. | |
374 | let is_in_effect = deprecation_in_effect(depr_attr); | |
375 | let lint = deprecation_lint(is_in_effect); | |
376 | if self.lint_level_at_node(lint, id).0 != Level::Allow { | |
5e7ed085 | 377 | let def_path = with_no_trimmed_paths!(self.def_path_str(def_id)); |
c295e0f8 XL |
378 | let def_kind = self.def_kind(def_id).descr(def_id); |
379 | ||
380 | late_report_deprecation( | |
381 | self, | |
382 | &deprecation_message( | |
383 | is_in_effect, | |
384 | depr_attr.since, | |
385 | depr_attr.note, | |
386 | def_kind, | |
5e7ed085 | 387 | &def_path, |
c295e0f8 XL |
388 | ), |
389 | depr_attr.suggestion, | |
390 | lint, | |
391 | span, | |
392 | method_span, | |
393 | id, | |
394 | def_id, | |
395 | ); | |
396 | } | |
0531ce1d | 397 | } |
476ff2be | 398 | }; |
476ff2be SL |
399 | } |
400 | ||
04454e1e | 401 | let is_staged_api = self.lookup_stability(def_id.krate.as_def_id()).is_some(); |
476ff2be | 402 | if !is_staged_api { |
0531ce1d | 403 | return EvalResult::Allow; |
9cc50fc6 | 404 | } |
476ff2be SL |
405 | |
406 | let stability = self.lookup_stability(def_id); | |
dfeec247 XL |
407 | debug!( |
408 | "stability: \ | |
409 | inspecting def_id={:?} span={:?} of stability={:?}", | |
410 | def_id, span, stability | |
411 | ); | |
476ff2be | 412 | |
85aaf69f | 413 | // Only the cross-crate scenario matters when checking unstable APIs |
476ff2be | 414 | let cross_crate = !def_id.is_local(); |
b039eaaf | 415 | if !cross_crate { |
0531ce1d | 416 | return EvalResult::Allow; |
b039eaaf SL |
417 | } |
418 | ||
0731742a | 419 | // Issue #38412: private items lack stability markers. |
dfeec247 | 420 | if skip_stability_check_due_to_privacy(self, def_id) { |
0531ce1d | 421 | return EvalResult::Allow; |
476ff2be | 422 | } |
85aaf69f | 423 | |
476ff2be | 424 | match stability { |
5e7ed085 | 425 | Some(Stability { |
416331ca XL |
426 | level: attr::Unstable { reason, issue, is_soft }, feature, .. |
427 | }) => { | |
48663c56 | 428 | if span.allows_unstable(feature) { |
9fa01778 XL |
429 | debug!("stability: skipping span={:?} since it is internal", span); |
430 | return EvalResult::Allow; | |
431 | } | |
5e7ed085 | 432 | if self.features().active(feature) { |
0531ce1d | 433 | return EvalResult::Allow; |
85aaf69f | 434 | } |
7cac9316 XL |
435 | |
436 | // When we're compiling the compiler itself we may pull in | |
437 | // crates from crates.io, but those crates may depend on other | |
438 | // crates also pulled in from crates.io. We want to ideally be | |
439 | // able to compile everything without requiring upstream | |
440 | // modifications, so in the case that this looks like a | |
0731742a | 441 | // `rustc_private` crate (e.g., a compiler crate) and we also have |
7cac9316 XL |
442 | // the `-Z force-unstable-if-unmarked` flag present (we're |
443 | // compiling a compiler crate), then let this missing feature | |
444 | // annotation slide. | |
60c5eb7d | 445 | if feature == sym::rustc_private && issue == NonZeroU32::new(27812) { |
7cac9316 | 446 | if self.sess.opts.debugging_opts.force_unstable_if_unmarked { |
0531ce1d | 447 | return EvalResult::Allow; |
7cac9316 XL |
448 | } |
449 | } | |
450 | ||
923072b8 FG |
451 | if matches!(allow_unstable, AllowUnstable::Yes) { |
452 | return EvalResult::Allow; | |
453 | } | |
454 | ||
3c0e092e XL |
455 | let suggestion = suggestion_for_allocator_api(self, def_id, span, feature); |
456 | EvalResult::Deny { feature, reason, issue, suggestion, is_soft } | |
0531ce1d XL |
457 | } |
458 | Some(_) => { | |
459 | // Stable APIs are always ok to call and deprecated APIs are | |
460 | // handled by the lint emitting logic above. | |
461 | EvalResult::Allow | |
462 | } | |
dfeec247 | 463 | None => EvalResult::Unmarked, |
0531ce1d XL |
464 | } |
465 | } | |
466 | ||
467 | /// Checks if an item is stable or error out. | |
468 | /// | |
469 | /// If the item defined by `def_id` is unstable and the corresponding `#![feature]` does not | |
470 | /// exist, emits an error. | |
471 | /// | |
1b1a35ee XL |
472 | /// This function will also check if the item is deprecated. |
473 | /// If so, and `id` is not `None`, a deprecated lint attached to `id` will be emitted. | |
17df50a5 XL |
474 | pub fn check_stability( |
475 | self, | |
476 | def_id: DefId, | |
477 | id: Option<HirId>, | |
478 | span: Span, | |
479 | method_span: Option<Span>, | |
480 | ) { | |
923072b8 FG |
481 | self.check_stability_allow_unstable(def_id, id, span, method_span, AllowUnstable::No) |
482 | } | |
483 | ||
484 | /// Checks if an item is stable or error out. | |
485 | /// | |
486 | /// If the item defined by `def_id` is unstable and the corresponding `#![feature]` does not | |
487 | /// exist, emits an error. | |
488 | /// | |
489 | /// This function will also check if the item is deprecated. | |
490 | /// If so, and `id` is not `None`, a deprecated lint attached to `id` will be emitted. | |
491 | /// | |
492 | /// Pass `AllowUnstable::Yes` to `allow_unstable` to force an unstable item to be allowed. Deprecation warnings will be emitted normally. | |
493 | pub fn check_stability_allow_unstable( | |
494 | self, | |
495 | def_id: DefId, | |
496 | id: Option<HirId>, | |
497 | span: Span, | |
498 | method_span: Option<Span>, | |
499 | allow_unstable: AllowUnstable, | |
500 | ) { | |
501 | self.check_optional_stability( | |
502 | def_id, | |
503 | id, | |
504 | span, | |
505 | method_span, | |
506 | allow_unstable, | |
507 | |span, def_id| { | |
508 | // The API could be uncallable for other reasons, for example when a private module | |
509 | // was referenced. | |
510 | self.sess.delay_span_bug(span, &format!("encountered unmarked API: {:?}", def_id)); | |
511 | }, | |
512 | ) | |
1b1a35ee XL |
513 | } |
514 | ||
515 | /// Like `check_stability`, except that we permit items to have custom behaviour for | |
516 | /// missing stability attributes (not necessarily just emit a `bug!`). This is necessary | |
517 | /// for default generic parameters, which only have stability attributes if they were | |
518 | /// added after the type on which they're defined. | |
519 | pub fn check_optional_stability( | |
520 | self, | |
521 | def_id: DefId, | |
522 | id: Option<HirId>, | |
523 | span: Span, | |
17df50a5 | 524 | method_span: Option<Span>, |
923072b8 | 525 | allow_unstable: AllowUnstable, |
29967ef6 | 526 | unmarked: impl FnOnce(Span, DefId), |
1b1a35ee | 527 | ) { |
74b04a01 XL |
528 | let soft_handler = |lint, span, msg: &_| { |
529 | self.struct_span_lint_hir(lint, id.unwrap_or(hir::CRATE_HIR_ID), span, |lint| { | |
5e7ed085 | 530 | lint.build(msg).emit(); |
74b04a01 XL |
531 | }) |
532 | }; | |
923072b8 | 533 | match self.eval_stability_allow_unstable(def_id, id, span, method_span, allow_unstable) { |
0531ce1d | 534 | EvalResult::Allow => {} |
3c0e092e XL |
535 | EvalResult::Deny { feature, reason, issue, suggestion, is_soft } => report_unstable( |
536 | self.sess, | |
537 | feature, | |
538 | reason, | |
539 | issue, | |
540 | suggestion, | |
541 | is_soft, | |
542 | span, | |
543 | soft_handler, | |
544 | ), | |
1b1a35ee | 545 | EvalResult::Unmarked => unmarked(span, def_id), |
85aaf69f SL |
546 | } |
547 | } | |
85aaf69f | 548 | |
a7813a04 | 549 | pub fn lookup_deprecation(self, id: DefId) -> Option<Deprecation> { |
5bcae85e SL |
550 | self.lookup_deprecation_entry(id).map(|depr| depr.attr) |
551 | } | |
1a4d82fc | 552 | } |