Skip to main content

rustc_attr_parsing/attributes/
allow_unstable.rs

1use std::iter;
2
3use rustc_ast::Const;
4use rustc_attr_ir::target::AstTarget;
5use rustc_feature::AttributeStability;
6
7use super::macro_attrs::check_macro_only;
8use super::prelude::*;
9use crate::diagnostics;
10
11pub(crate) struct AllowInternalUnstableParser;
12impl CombineAttributeParser for AllowInternalUnstableParser {
13    const PATH: &[Symbol] = &[sym::allow_internal_unstable];
14    type Item = (Symbol, Span);
15    const CONVERT: ConvertFn<Self::Item> =
16        |items, span| AttributeKind::AllowInternalUnstable(items, span);
17    const ALLOWED_TARGETS: AllowedTargets<'_> =
18        AllowedTargets::AllowList(&[Allow(Target::MacroDef), Allow(Target::Fn)]);
19    const TEMPLATE: AttributeTemplate = crate::AttributeTemplate {
    word: true,
    list: Some(&["feat1, feat2, ..."]),
    one_of: &[],
    name_value_str: None,
    docs: None,
}template!(Word, List: &["feat1, feat2, ..."]);
20    const STABILITY: AttributeStability = {
    _ = rustc_feature::Features::allow_internal_unstable;
    AttributeStability::Unstable {
        gate_name: rustc_span::sym::allow_internal_unstable,
        notes: &[],
    }
}unstable!(allow_internal_unstable);
21
22    fn extend(
23        cx: &mut AcceptContext<'_, '_>,
24        args: &ArgParser,
25    ) -> impl IntoIterator<Item = Self::Item> {
26        parse_unstable(cx, args, <Self as CombineAttributeParser>::PATH[0])
27            .into_iter()
28            .zip(iter::repeat(cx.attr_span))
29    }
30
31    fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) {
32        check_macro_only(cx, attr_span);
33    }
34}
35
36pub(crate) struct UnstableFeatureBoundParser;
37impl CombineAttributeParser for UnstableFeatureBoundParser {
38    const PATH: &[rustc_span::Symbol] = &[sym::unstable_feature_bound];
39    type Item = (Symbol, Span);
40    const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::UnstableFeatureBound(items);
41    const STABILITY: AttributeStability = {
    _ = rustc_feature::Features::staged_api;
    AttributeStability::Unstable {
        gate_name: rustc_span::sym::staged_api,
        notes: &[],
    }
}unstable!(staged_api);
42    const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
43        Allow(Target::Fn),
44        Allow(Target::Impl { of_trait: true }),
45        Allow(Target::Trait),
46    ]);
47    const TEMPLATE: AttributeTemplate = crate::AttributeTemplate {
    word: true,
    list: Some(&["feat1, feat2, ..."]),
    one_of: &[],
    name_value_str: None,
    docs: None,
}template!(Word, List: &["feat1, feat2, ..."]);
48
49    fn extend(
50        cx: &mut AcceptContext<'_, '_>,
51        args: &ArgParser,
52    ) -> impl IntoIterator<Item = Self::Item> {
53        parse_unstable(cx, args, <Self as CombineAttributeParser>::PATH[0])
54            .into_iter()
55            .zip(iter::repeat(cx.attr_span))
56    }
57}
58
59pub(crate) struct RustcAllowConstFnUnstableParser;
60impl CombineAttributeParser for RustcAllowConstFnUnstableParser {
61    const PATH: &[Symbol] = &[sym::rustc_allow_const_fn_unstable];
62    type Item = Symbol;
63    const CONVERT: ConvertFn<Self::Item> =
64        |items, first_span| AttributeKind::RustcAllowConstFnUnstable(items, first_span);
65    const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
66        Allow(Target::Fn),
67        Allow(Target::Method(MethodKind::Inherent)),
68        Allow(Target::Method(MethodKind::Trait { body: true })),
69        Allow(Target::Method(MethodKind::TraitImpl)),
70    ]);
71    const TEMPLATE: AttributeTemplate = crate::AttributeTemplate {
    word: true,
    list: Some(&["feat1, feat2, ..."]),
    one_of: &[],
    name_value_str: None,
    docs: None,
}template!(Word, List: &["feat1, feat2, ..."]);
72    const STABILITY: AttributeStability = {
    _ = rustc_feature::Features::rustc_attrs;
    AttributeStability::Unstable {
        gate_name: rustc_span::sym::rustc_attrs,
        notes: &["rustc_allow_const_fn_unstable side-steps feature gating and stability checks"],
    }
}unstable!(
73        rustc_attrs,
74        "rustc_allow_const_fn_unstable side-steps feature gating and stability checks"
75    );
76
77    fn extend(
78        cx: &mut AcceptContext<'_, '_>,
79        args: &ArgParser,
80    ) -> impl IntoIterator<Item = Self::Item> {
81        parse_unstable(cx, args, <Self as CombineAttributeParser>::PATH[0])
82    }
83
84    fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) {
85        match cx.ast_target {
86            AstTarget::Fn(_) | AstTarget::Method(..) => {
87                let fn_sig =
88                    cx.ast_target.get_fn_sig().expect("missing fn signature for AST target");
89                if #[allow(non_exhaustive_omitted_patterns)] match fn_sig.header.constness {
    Const::No => true,
    _ => false,
}matches!(fn_sig.header.constness, Const::No) {
90                    cx.emit_err(diagnostics::RustcAllowConstFnUnstable {
91                        attr_span,
92                        span: cx.target_span,
93                    });
94                }
95            }
96            _ => {}
97        }
98    }
99}
100
101fn parse_unstable(
102    cx: &AcceptContext<'_, '_>,
103    args: &ArgParser,
104    symbol: Symbol,
105) -> impl IntoIterator<Item = Symbol> {
106    let mut res = Vec::new();
107
108    let Some(list) = args.as_list() else {
109        cx.emit_err(diagnostics::ExpectsFeatureList {
110            span: cx.attr_span,
111            name: symbol.to_ident_string(),
112        });
113        return res;
114    };
115
116    for param in list.mixed() {
117        let param_span = param.span();
118        if let Some(ident) = param.meta_item_no_args().and_then(|i| i.path().word()) {
119            res.push(ident.name);
120        } else {
121            cx.emit_err(diagnostics::ExpectsFeatures {
122                span: param_span,
123                name: symbol.to_ident_string(),
124            });
125        }
126    }
127
128    res
129}