rustc_attr_parsing/attributes/
prototype.rs1use rustc_feature::{AttributeTemplate, template};
4use rustc_hir::Target;
5use rustc_hir::attrs::{AttributeKind, MirDialect, MirPhase};
6use rustc_span::{Span, Symbol, sym};
7
8use super::{AttributeOrder, OnDuplicate};
9use crate::attributes::SingleAttributeParser;
10use crate::context::{AcceptContext, Stage};
11use crate::parser::ArgParser;
12use crate::target_checking::AllowedTargets;
13use crate::target_checking::Policy::Allow;
14
15pub(crate) struct CustomMirParser;
16
17impl<S: Stage> SingleAttributeParser<S> for CustomMirParser {
18 const PATH: &[rustc_span::Symbol] = &[sym::custom_mir];
19
20 const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
21
22 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
23
24 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
25
26 const TEMPLATE: AttributeTemplate = template!(List: &[r#"dialect = "...", phase = "...""#]);
27
28 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
29 let Some(list) = args.list() else {
30 cx.expected_list(cx.attr_span);
31 return None;
32 };
33
34 let mut dialect = None;
35 let mut phase = None;
36 let mut failed = false;
37
38 for item in list.mixed() {
39 let Some(meta_item) = item.meta_item() else {
40 cx.expected_name_value(item.span(), None);
41 failed = true;
42 break;
43 };
44
45 if let Some(arg) = meta_item.word_is(sym::dialect) {
46 extract_value(cx, sym::dialect, arg, meta_item.span(), &mut dialect, &mut failed);
47 } else if let Some(arg) = meta_item.word_is(sym::phase) {
48 extract_value(cx, sym::phase, arg, meta_item.span(), &mut phase, &mut failed);
49 } else if let Some(word) = meta_item.path().word() {
50 let word = word.to_string();
51 cx.unknown_key(meta_item.span(), word, &["dialect", "phase"]);
52 failed = true;
53 } else {
54 cx.expected_name_value(meta_item.span(), None);
55 failed = true;
56 };
57 }
58
59 let dialect = parse_dialect(cx, dialect, &mut failed);
60 let phase = parse_phase(cx, phase, &mut failed);
61
62 if failed {
63 return None;
64 }
65
66 Some(AttributeKind::CustomMir(dialect, phase, cx.attr_span))
67 }
68}
69
70fn extract_value<S: Stage>(
71 cx: &mut AcceptContext<'_, '_, S>,
72 key: Symbol,
73 arg: &ArgParser<'_>,
74 span: Span,
75 out_val: &mut Option<(Symbol, Span)>,
76 failed: &mut bool,
77) {
78 if out_val.is_some() {
79 cx.duplicate_key(span, key);
80 *failed = true;
81 return;
82 }
83
84 let Some(val) = arg.name_value() else {
85 cx.expected_single_argument(arg.span().unwrap_or(span));
86 *failed = true;
87 return;
88 };
89
90 let Some(value_sym) = val.value_as_str() else {
91 cx.expected_string_literal(val.value_span, Some(val.value_as_lit()));
92 *failed = true;
93 return;
94 };
95
96 *out_val = Some((value_sym, val.value_span));
97}
98
99fn parse_dialect<S: Stage>(
100 cx: &mut AcceptContext<'_, '_, S>,
101 dialect: Option<(Symbol, Span)>,
102 failed: &mut bool,
103) -> Option<(MirDialect, Span)> {
104 let (dialect, span) = dialect?;
105
106 let dialect = match dialect {
107 sym::analysis => MirDialect::Analysis,
108 sym::built => MirDialect::Built,
109 sym::runtime => MirDialect::Runtime,
110
111 _ => {
112 cx.expected_specific_argument(span, &[sym::analysis, sym::built, sym::runtime]);
113 *failed = true;
114 return None;
115 }
116 };
117
118 Some((dialect, span))
119}
120
121fn parse_phase<S: Stage>(
122 cx: &mut AcceptContext<'_, '_, S>,
123 phase: Option<(Symbol, Span)>,
124 failed: &mut bool,
125) -> Option<(MirPhase, Span)> {
126 let (phase, span) = phase?;
127
128 let phase = match phase {
129 sym::initial => MirPhase::Initial,
130 sym::post_cleanup => MirPhase::PostCleanup,
131 sym::optimized => MirPhase::Optimized,
132
133 _ => {
134 cx.expected_specific_argument(span, &[sym::initial, sym::post_cleanup, sym::optimized]);
135 *failed = true;
136 return None;
137 }
138 };
139
140 Some((phase, span))
141}