Skip to main content

rustc_attr_parsing/
stability.rs

1use rustc_attr_ir::AttrPath;
2use rustc_feature::AttributeStability;
3use rustc_session::diagnostics::feature_err;
4use rustc_span::{Span, sym};
5
6use crate::{AttributeParser, ShouldEmit};
7
8#[macro_export]
9macro_rules! unstable {
10    ($feat: ident $(, $notes:expr)*) => {{
11        // Check that the feature exists
12        _ = rustc_feature::Features::$feat;
13
14        AttributeStability::Unstable {
15            gate_name: rustc_span::sym::$feat,
16            notes: &[$($notes),*],
17        }
18    }};
19}
20
21impl<'sess> AttributeParser<'sess> {
22    pub fn check_attribute_stability(
23        &mut self,
24        attr_path: &AttrPath,
25        attr_span: Span,
26        expected_stability: AttributeStability,
27    ) {
28        if #[allow(non_exhaustive_omitted_patterns)] match self.should_emit {
    ShouldEmit::Nothing => true,
    _ => false,
}matches!(self.should_emit, ShouldEmit::Nothing) {
29            return;
30        }
31
32        let AttributeStability::Unstable { gate_name, notes } = expected_stability else {
33            return;
34        };
35
36        if self.features().enabled(gate_name) || attr_span.allows_unstable(gate_name) {
37            return;
38        }
39
40        let (explain, default_notes): (String, &[String]) = match gate_name {
41            sym::rustc_attrs => ("use of an internal attribute".to_string(), &[
42                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("the `{0}` attribute is an internal implementation detail that will never be stable",
                attr_path))
    })format!("the `{attr_path}` attribute is an internal implementation detail that will never be stable"
43            )]),
44            sym::staged_api => ("stability attributes may not be used outside of the standard library".to_string(), &[]),
45            sym::custom_mir => ("the `custom_mir` attribute is just used for the Rust test suite".to_string(), &[]),
46            sym::allow_internal_unsafe => ("the `allow_internal_unsafe` attribute side-steps the `unsafe_code` lint".to_string(), &[]),
47            sym::allow_internal_unstable => ("the `allow_internal_unstable` attribute side-steps feature gating and stability checks".to_string(), &[]),
48            sym::compiler_builtins => ("the `compiler_builtins` attribute is used to identify the `compiler_builtins` crate which contains compiler-rt intrinsics and will never be stable".to_string(), &[]),
49            sym::custom_test_frameworks => ("custom test frameworks are an unstable feature".to_string(), &[]),
50            sym::linkage => ("the `linkage` attribute is experimental and not portable across platforms".to_string(), &[]),
51            sym::dropck_eyepatch => ("the `may_dangle` attribute has unstable semantics and may be removed in the future".to_string(), &[]),
52            sym::intrinsics => ("the `rustc_intrinsic` attribute is used to declare intrinsics as function items".to_string(), &[]),
53            sym::lang_items => ("lang items are subject to change".to_string(), &[]),
54            sym::prelude_import => ("the `prelude_import` attribute is for use by rustc only".to_string(), &[]),
55            sym::profiler_runtime => ("the `profiler_runtime` attribute is used to identify the `profiler_builtins` crate which contains the profiler runtime and will never be stable".to_string(), &[]),
56            sym::thread_local => ("the `thread_local` attribute is an experimental feature, and does not currently handle destructors".to_string(), &[]),
57            sym::rustdoc_internals => ("this subset of the `doc` attribute is meant for internal use only".to_string(), &[]),
58            sym::doc_notable_trait => ("the `doc(notable_trait)` attribute is experimental".to_string(), &[]),
59            sym::doc_cfg => ("the `doc(cfg)` and `doc(auto_cfg)` attributes are experimental".to_string(), &[]),
60            sym::doc_masked => ("the `doc(masked)` attribute is experimental".to_string(), &[]),
61            _ => (::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("the `{0}` attribute is an experimental feature",
                attr_path))
    })format!("the `{attr_path}` attribute is an experimental feature"), &[]),
62        };
63
64        // For unstable subsets of an attribute, point at that
65        let err_span = if #[allow(non_exhaustive_omitted_patterns)] match gate_name {
    sym::rustdoc_internals | sym::doc_notable_trait | sym::doc_cfg |
        sym::doc_masked => true,
    _ => false,
}matches!(
66            gate_name,
67            sym::rustdoc_internals | sym::doc_notable_trait | sym::doc_cfg | sym::doc_masked
68        ) {
69            attr_span
70        } else {
71            attr_path.span
72        };
73
74        let mut diag = feature_err(self.sess, gate_name, err_span, explain);
75
76        // Remove the suggestion for `#![feature(staged_api)]` as these attributes are currently
77        // not usable outside std. If we do ever expose `#[stable]` etc under a different feature
78        // name then it would be unfortunate to have nightlies out there suggesting `staged_api`.
79        if gate_name == sym::staged_api {
80            diag.children.clear();
81        }
82
83        for note in default_notes {
84            diag.note(note.clone());
85        }
86        for note in notes {
87            diag.note(*note);
88        }
89
90        diag.emit();
91    }
92}