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