Skip to main content

rustc_attr_parsing/
stability.rs

1use rustc_feature::AttributeStability;
2use rustc_hir::AttrPath;
3use rustc_session::errors::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        AttributeStability::Unstable {
12            gate_name: rustc_span::sym::$feat,
13            gate_check: rustc_feature::Features::$feat,
14            notes: &[$($notes),*],
15        }
16    };
17}
18
19impl<'sess> AttributeParser<'sess> {
20    pub fn check_attribute_stability(
21        &mut self,
22        attr_path: &AttrPath,
23        attr_span: Span,
24        expected_stability: AttributeStability,
25    ) {
26        if #[allow(non_exhaustive_omitted_patterns)] match self.should_emit {
    ShouldEmit::Nothing => true,
    _ => false,
}matches!(self.should_emit, ShouldEmit::Nothing) {
27            return;
28        }
29
30        let AttributeStability::Unstable { gate_check, gate_name, notes } = expected_stability
31        else {
32            return;
33        };
34
35        if gate_check(self.features()) || attr_span.allows_unstable(gate_name) {
36            return;
37        }
38
39        let (explain, default_notes): (String, &[String]) = match gate_name {
40            sym::rustc_attrs => ("use of an internal attribute".to_string(), &[
41                ::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"
42            )]),
43            sym::staged_api => ("stability attributes may not be used outside of the standard library".to_string(), &[]),
44            sym::custom_mir => ("the `#[custom_mir]` attribute is just used for the Rust test suite".to_string(), &[]),
45            sym::allow_internal_unsafe => ("allow_internal_unsafe side-steps the unsafe_code lint".to_string(), &[]),
46            sym::allow_internal_unstable => ("allow_internal_unstable side-steps feature gating and stability checks".to_string(), &[]),
47            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(), &[]),
48            sym::custom_test_frameworks => ("custom test frameworks are an unstable feature".to_string(), &[]),
49            sym::linkage => ("the `linkage` attribute is experimental and not portable across platforms".to_string(), &[]),
50            sym::dropck_eyepatch => ("`may_dangle` has unstable semantics and may be removed in the future".to_string(), &[]),
51            sym::intrinsics => ("the `#[rustc_intrinsic]` attribute is used to declare intrinsics as function items".to_string(), &[]),
52            sym::lang_items => ("lang items are subject to change".to_string(), &[]),
53            sym::prelude_import => ("`#[prelude_import]` is for use by rustc only".to_string(), &[]),
54            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(), &[]),
55            sym::thread_local => ("`#[thread_local]` is an experimental feature, and does not currently handle destructors".to_string(), &[]),
56            _ => (::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"), &[]),
57        };
58
59        let mut diag = feature_err(self.sess, gate_name, attr_span, explain);
60
61        // Remove the suggestion for `#![feature(staged_api)]` as these attributes are currently
62        // not usable outside std. If we do ever expose `#[stable]` etc under a different feature
63        // name then it would be unfortunate to have nightlies out there suggesting `staged_api`.
64        if gate_name == sym::staged_api {
65            diag.children.clear();
66        }
67
68        for note in default_notes {
69            diag.note(note.clone());
70        }
71        for note in notes {
72            diag.note(*note);
73        }
74
75        diag.emit();
76    }
77}