rustc_attr_parsing/attributes/
repr.rs1use rustc_abi::Align;
2use rustc_ast::{IntTy, LitIntType, LitKind, UintTy};
3use rustc_attr_data_structures::{AttributeKind, IntType, ReprAttr};
4use rustc_span::{DUMMY_SP, 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 [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 (name, ident_span) = if let Some(ident) = param.path_without_args().word() {
100 (Some(ident.name), ident.span)
101 } else {
102 (None, DUMMY_SP)
103 };
104
105 let args = param.args();
106
107 match (name, args) {
108 (Some(sym::align), ArgParser::NoArgs) => {
109 cx.emit_err(session_diagnostics::InvalidReprAlignNeedArg { span: ident_span });
110 None
111 }
112 (Some(sym::align), ArgParser::List(l)) => {
113 parse_repr_align(cx, l, param.span(), AlignKind::Align)
114 }
115
116 (Some(sym::packed), ArgParser::NoArgs) => Some(ReprPacked(Align::ONE)),
117 (Some(sym::packed), ArgParser::List(l)) => {
118 parse_repr_align(cx, l, param.span(), AlignKind::Packed)
119 }
120
121 (Some(name @ sym::align | name @ sym::packed), ArgParser::NameValue(l)) => {
122 cx.emit_err(session_diagnostics::IncorrectReprFormatGeneric {
123 span: param.span(),
124 repr_arg: name,
126 cause: IncorrectReprFormatGenericCause::from_lit_kind(
127 param.span(),
128 &l.value_as_lit().kind,
129 name,
130 ),
131 });
132 None
133 }
134
135 (Some(sym::Rust), ArgParser::NoArgs) => Some(ReprRust),
136 (Some(sym::C), ArgParser::NoArgs) => Some(ReprC),
137 (Some(sym::simd), ArgParser::NoArgs) => Some(ReprSimd),
138 (Some(sym::transparent), ArgParser::NoArgs) => Some(ReprTransparent),
139 (Some(name @ int_pat!()), ArgParser::NoArgs) => {
140 Some(ReprInt(int_type_of_word(name).unwrap()))
142 }
143
144 (
145 Some(
146 name @ sym::Rust
147 | name @ sym::C
148 | name @ sym::simd
149 | name @ sym::transparent
150 | name @ int_pat!(),
151 ),
152 ArgParser::NameValue(_),
153 ) => {
154 cx.emit_err(session_diagnostics::InvalidReprHintNoValue { span: param.span(), name });
155 None
156 }
157 (
158 Some(
159 name @ sym::Rust
160 | name @ sym::C
161 | name @ sym::simd
162 | name @ sym::transparent
163 | name @ int_pat!(),
164 ),
165 ArgParser::List(_),
166 ) => {
167 cx.emit_err(session_diagnostics::InvalidReprHintNoParen { span: param.span(), name });
168 None
169 }
170
171 _ => {
172 cx.emit_err(session_diagnostics::UnrecognizedReprHint { span: param.span() });
173 None
174 }
175 }
176}
177
178enum AlignKind {
179 Packed,
180 Align,
181}
182
183fn parse_repr_align(
184 cx: &AcceptContext<'_>,
185 list: &MetaItemListParser<'_>,
186 param_span: Span,
187 align_kind: AlignKind,
188) -> Option<ReprAttr> {
189 use AlignKind::*;
190
191 let Some(align) = list.single() else {
192 match align_kind {
193 Packed => {
194 cx.emit_err(session_diagnostics::IncorrectReprFormatPackedOneOrZeroArg {
195 span: param_span,
196 });
197 }
198 Align => {
199 cx.dcx().emit_err(session_diagnostics::IncorrectReprFormatAlignOneArg {
200 span: param_span,
201 });
202 }
203 }
204
205 return None;
206 };
207
208 let Some(lit) = align.lit() else {
209 match align_kind {
210 Packed => {
211 cx.emit_err(session_diagnostics::IncorrectReprFormatPackedExpectInteger {
212 span: align.span(),
213 });
214 }
215 Align => {
216 cx.emit_err(session_diagnostics::IncorrectReprFormatExpectInteger {
217 span: align.span(),
218 });
219 }
220 }
221
222 return None;
223 };
224
225 match parse_alignment(&lit.kind) {
226 Ok(literal) => Some(match align_kind {
227 AlignKind::Packed => ReprAttr::ReprPacked(literal),
228 AlignKind::Align => ReprAttr::ReprAlign(literal),
229 }),
230 Err(message) => {
231 cx.emit_err(session_diagnostics::InvalidReprGeneric {
232 span: lit.span,
233 repr_arg: match align_kind {
234 Packed => "packed".to_string(),
235 Align => "align".to_string(),
236 },
237 error_part: message,
238 });
239 None
240 }
241 }
242}
243
244fn parse_alignment(node: &LitKind) -> Result<Align, &'static str> {
245 if let LitKind::Int(literal, LitIntType::Unsuffixed) = node {
246 if literal.get().is_power_of_two() {
248 literal
250 .get()
251 .try_into()
252 .ok()
253 .and_then(|v| Align::from_bytes(v).ok())
254 .ok_or("larger than 2^29")
255 } else {
256 Err("not a power of two")
257 }
258 } else {
259 Err("not an unsuffixed integer")
260 }
261}