rustc_attr_parsing/attributes/
allow_unstable.rs1use 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}