rustc_attr_parsing/attributes/
repr.rs
1use rustc_abi::Align;
2use rustc_ast::{IntTy, LitIntType, LitKind, UintTy};
3use rustc_attr_data_structures::{AttributeKind, IntType, ReprAttr};
4use rustc_span::{Span, Symbol, sym};
5
6use super::{CombineAttributeParser, ConvertFn};
7use crate::context::AcceptContext;
8use crate::parser::{ArgParser, MetaItemListParser, MetaItemParser};
9use crate::session_diagnostics;
10use crate::session_diagnostics::IncorrectReprFormatGenericCause;
11
12pub(crate) struct ReprParser;
21
22impl CombineAttributeParser for ReprParser {
23 type Item = (ReprAttr, Span);
24 const PATH: &'static [rustc_span::Symbol] = &[sym::repr];
25 const CONVERT: ConvertFn<Self::Item> = AttributeKind::Repr;
26
27 fn extend<'a>(
28 cx: &'a AcceptContext<'a>,
29 args: &'a ArgParser<'a>,
30 ) -> impl IntoIterator<Item = Self::Item> + 'a {
31 let mut reprs = Vec::new();
32
33 let Some(list) = args.list() else {
34 return reprs;
35 };
36
37 if list.is_empty() {
38 reprs.push((ReprAttr::ReprEmpty, cx.attr_span));
40 }
41
42 for param in list.mixed() {
43 if let Some(_) = param.lit() {
44 cx.emit_err(session_diagnostics::ReprIdent { span: cx.attr_span });
45 continue;
46 }
47
48 reprs.extend(
49 param.meta_item().and_then(|mi| parse_repr(cx, &mi)).map(|r| (r, param.span())),
50 );
51 }
52
53 reprs
54 }
55}
56
57macro_rules! int_pat {
58 () => {
59 sym::i8
60 | sym::u8
61 | sym::i16
62 | sym::u16
63 | sym::i32
64 | sym::u32
65 | sym::i64
66 | sym::u64
67 | sym::i128
68 | sym::u128
69 | sym::isize
70 | sym::usize
71 };
72}
73
74fn int_type_of_word(s: Symbol) -> Option<IntType> {
75 use IntType::*;
76
77 match s {
78 sym::i8 => Some(SignedInt(IntTy::I8)),
79 sym::u8 => Some(UnsignedInt(UintTy::U8)),
80 sym::i16 => Some(SignedInt(IntTy::I16)),
81 sym::u16 => Some(UnsignedInt(UintTy::U16)),
82 sym::i32 => Some(SignedInt(IntTy::I32)),
83 sym::u32 => Some(UnsignedInt(UintTy::U32)),
84 sym::i64 => Some(SignedInt(IntTy::I64)),
85 sym::u64 => Some(UnsignedInt(UintTy::U64)),
86 sym::i128 => Some(SignedInt(IntTy::I128)),
87 sym::u128 => Some(UnsignedInt(UintTy::U128)),
88 sym::isize => Some(SignedInt(IntTy::Isize)),
89 sym::usize => Some(UnsignedInt(UintTy::Usize)),
90 _ => None,
91 }
92}
93
94fn parse_repr(cx: &AcceptContext<'_>, param: &MetaItemParser<'_>) -> Option<ReprAttr> {
95 use ReprAttr::*;
96
97 let (ident, args) = param.word_or_empty();
100
101 match (ident.name, args) {
102 (sym::align, ArgParser::NoArgs) => {
103 cx.emit_err(session_diagnostics::InvalidReprAlignNeedArg { span: ident.span });
104 None
105 }
106 (sym::align, ArgParser::List(l)) => parse_repr_align(cx, l, param.span(), AlignKind::Align),
107
108 (sym::packed, ArgParser::NoArgs) => Some(ReprPacked(Align::ONE)),
109 (sym::packed, ArgParser::List(l)) => {
110 parse_repr_align(cx, l, param.span(), AlignKind::Packed)
111 }
112
113 (sym::align | sym::packed, ArgParser::NameValue(l)) => {
114 cx.emit_err(session_diagnostics::IncorrectReprFormatGeneric {
115 span: param.span(),
116 repr_arg: &ident.to_string(),
118 cause: IncorrectReprFormatGenericCause::from_lit_kind(
119 param.span(),
120 &l.value_as_lit().kind,
121 ident.name.as_str(),
122 ),
123 });
124 None
125 }
126
127 (sym::Rust, ArgParser::NoArgs) => Some(ReprRust),
128 (sym::C, ArgParser::NoArgs) => Some(ReprC),
129 (sym::simd, ArgParser::NoArgs) => Some(ReprSimd),
130 (sym::transparent, ArgParser::NoArgs) => Some(ReprTransparent),
131 (i @ int_pat!(), ArgParser::NoArgs) => {
132 Some(ReprInt(int_type_of_word(i).unwrap()))
134 }
135
136 (
137 sym::Rust | sym::C | sym::simd | sym::transparent | int_pat!(),
138 ArgParser::NameValue(_),
139 ) => {
140 cx.emit_err(session_diagnostics::InvalidReprHintNoValue {
141 span: param.span(),
142 name: ident.to_string(),
143 });
144 None
145 }
146 (sym::Rust | sym::C | sym::simd | sym::transparent | int_pat!(), ArgParser::List(_)) => {
147 cx.emit_err(session_diagnostics::InvalidReprHintNoParen {
148 span: param.span(),
149 name: ident.to_string(),
150 });
151 None
152 }
153
154 _ => {
155 cx.emit_err(session_diagnostics::UnrecognizedReprHint { span: param.span() });
156 None
157 }
158 }
159}
160
161enum AlignKind {
162 Packed,
163 Align,
164}
165
166fn parse_repr_align(
167 cx: &AcceptContext<'_>,
168 list: &MetaItemListParser<'_>,
169 param_span: Span,
170 align_kind: AlignKind,
171) -> Option<ReprAttr> {
172 use AlignKind::*;
173
174 let Some(align) = list.single() else {
175 match align_kind {
176 Packed => {
177 cx.emit_err(session_diagnostics::IncorrectReprFormatPackedOneOrZeroArg {
178 span: param_span,
179 });
180 }
181 Align => {
182 cx.dcx().emit_err(session_diagnostics::IncorrectReprFormatAlignOneArg {
183 span: param_span,
184 });
185 }
186 }
187
188 return None;
189 };
190
191 let Some(lit) = align.lit() else {
192 match align_kind {
193 Packed => {
194 cx.emit_err(session_diagnostics::IncorrectReprFormatPackedExpectInteger {
195 span: align.span(),
196 });
197 }
198 Align => {
199 cx.emit_err(session_diagnostics::IncorrectReprFormatExpectInteger {
200 span: align.span(),
201 });
202 }
203 }
204
205 return None;
206 };
207
208 match parse_alignment(&lit.kind) {
209 Ok(literal) => Some(match align_kind {
210 AlignKind::Packed => ReprAttr::ReprPacked(literal),
211 AlignKind::Align => ReprAttr::ReprAlign(literal),
212 }),
213 Err(message) => {
214 cx.emit_err(session_diagnostics::InvalidReprGeneric {
215 span: lit.span,
216 repr_arg: match align_kind {
217 Packed => "packed".to_string(),
218 Align => "align".to_string(),
219 },
220 error_part: message,
221 });
222 None
223 }
224 }
225}
226
227fn parse_alignment(node: &LitKind) -> Result<Align, &'static str> {
228 if let LitKind::Int(literal, LitIntType::Unsuffixed) = node {
229 if literal.get().is_power_of_two() {
231 literal
233 .get()
234 .try_into()
235 .ok()
236 .and_then(|v| Align::from_bytes(v).ok())
237 .ok_or("larger than 2^29")
238 } else {
239 Err("not a power of two")
240 }
241 } else {
242 Err("not an unsuffixed integer")
243 }
244}