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