rustc_attr_parsing/attributes/
repr.rs1use rustc_abi::{Align, Size};
2use rustc_ast::{IntTy, LitIntType, LitKind, UintTy};
3use rustc_hir::attrs::{IntType, ReprAttr};
4
5use super::prelude::*;
6use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause};
7
8pub(crate) struct ReprParser;
17
18impl<S: Stage> CombineAttributeParser<S> for ReprParser {
19 type Item = (ReprAttr, Span);
20 const PATH: &[Symbol] = &[sym::repr];
21 const CONVERT: ConvertFn<Self::Item> =
22 |items, first_span| AttributeKind::Repr { reprs: items, first_span };
23 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: false,
list: Some(&["C", "Rust", "transparent", "align(...)", "packed(...)",
"<integer type>"]),
one_of: &[],
name_value_str: None,
docs: Some("https://doc.rust-lang.org/reference/type-layout.html#representations"),
}template!(
25 List: &["C", "Rust", "transparent", "align(...)", "packed(...)", "<integer type>"],
26 "https://doc.rust-lang.org/reference/type-layout.html#representations"
27 );
28
29 fn extend(
30 cx: &mut AcceptContext<'_, '_, S>,
31 args: &ArgParser,
32 ) -> impl IntoIterator<Item = Self::Item> {
33 let mut reprs = Vec::new();
34
35 let Some(list) = args.list() else {
36 let attr_span = cx.attr_span;
37 cx.adcx().expected_list(attr_span, args);
38 return reprs;
39 };
40
41 if list.is_empty() {
42 let attr_span = cx.attr_span;
43 cx.adcx().warn_empty_attribute(attr_span);
44 return reprs;
45 }
46
47 for param in list.mixed() {
48 if let Some(_) = param.lit() {
49 cx.emit_err(session_diagnostics::ReprIdent { span: cx.attr_span });
50 continue;
51 }
52
53 reprs.extend(
54 param.meta_item().and_then(|mi| parse_repr(cx, &mi)).map(|r| (r, param.span())),
55 );
56 }
57
58 reprs
59 }
60
61 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
64}
65
66macro_rules! int_pat {
67 () => {
68 sym::i8
69 | sym::u8
70 | sym::i16
71 | sym::u16
72 | sym::i32
73 | sym::u32
74 | sym::i64
75 | sym::u64
76 | sym::i128
77 | sym::u128
78 | sym::isize
79 | sym::usize
80 };
81}
82
83fn int_type_of_word(s: Symbol) -> Option<IntType> {
84 use IntType::*;
85
86 match s {
87 sym::i8 => Some(SignedInt(IntTy::I8)),
88 sym::u8 => Some(UnsignedInt(UintTy::U8)),
89 sym::i16 => Some(SignedInt(IntTy::I16)),
90 sym::u16 => Some(UnsignedInt(UintTy::U16)),
91 sym::i32 => Some(SignedInt(IntTy::I32)),
92 sym::u32 => Some(UnsignedInt(UintTy::U32)),
93 sym::i64 => Some(SignedInt(IntTy::I64)),
94 sym::u64 => Some(UnsignedInt(UintTy::U64)),
95 sym::i128 => Some(SignedInt(IntTy::I128)),
96 sym::u128 => Some(UnsignedInt(UintTy::U128)),
97 sym::isize => Some(SignedInt(IntTy::Isize)),
98 sym::usize => Some(UnsignedInt(UintTy::Usize)),
99 _ => None,
100 }
101}
102
103fn parse_repr<S: Stage>(cx: &AcceptContext<'_, '_, S>, param: &MetaItemParser) -> Option<ReprAttr> {
104 use ReprAttr::*;
105
106 let (name, ident_span) = if let Some(ident) = param.path().word() {
109 (Some(ident.name), ident.span)
110 } else {
111 (None, DUMMY_SP)
112 };
113
114 let args = param.args();
115
116 match (name, args) {
117 (Some(sym::align), ArgParser::NoArgs) => {
118 cx.emit_err(session_diagnostics::InvalidReprAlignNeedArg { span: ident_span });
119 None
120 }
121 (Some(sym::align), ArgParser::List(l)) => {
122 parse_repr_align(cx, l, param.span(), AlignKind::Align)
123 }
124
125 (Some(sym::packed), ArgParser::NoArgs) => Some(ReprPacked(Align::ONE)),
126 (Some(sym::packed), ArgParser::List(l)) => {
127 parse_repr_align(cx, l, param.span(), AlignKind::Packed)
128 }
129
130 (Some(name @ sym::align | name @ sym::packed), ArgParser::NameValue(l)) => {
131 cx.emit_err(session_diagnostics::IncorrectReprFormatGeneric {
132 span: param.span(),
133 repr_arg: name,
135 cause: IncorrectReprFormatGenericCause::from_lit_kind(
136 param.span(),
137 &l.value_as_lit().kind,
138 name,
139 ),
140 });
141 None
142 }
143
144 (Some(sym::Rust), ArgParser::NoArgs) => Some(ReprRust),
145 (Some(sym::C), ArgParser::NoArgs) => Some(ReprC),
146 (Some(sym::simd), ArgParser::NoArgs) => Some(ReprSimd),
147 (Some(sym::transparent), ArgParser::NoArgs) => Some(ReprTransparent),
148 (Some(name @ sym::i8 | sym::u8 | sym::i16 | sym::u16 | sym::i32 | sym::u32 | sym::i64 |
sym::u64 | sym::i128 | sym::u128 | sym::isize | sym::usizeint_pat!()), ArgParser::NoArgs) => {
149 Some(ReprInt(int_type_of_word(name).unwrap()))
151 }
152
153 (
154 Some(
155 name @ sym::Rust
156 | name @ sym::C
157 | name @ sym::simd
158 | name @ sym::transparent
159 | name @ sym::i8 | sym::u8 | sym::i16 | sym::u16 | sym::i32 | sym::u32 | sym::i64 |
sym::u64 | sym::i128 | sym::u128 | sym::isize | sym::usizeint_pat!(),
160 ),
161 ArgParser::NameValue(_),
162 ) => {
163 cx.emit_err(session_diagnostics::InvalidReprHintNoValue { span: param.span(), name });
164 None
165 }
166 (
167 Some(
168 name @ sym::Rust
169 | name @ sym::C
170 | name @ sym::simd
171 | name @ sym::transparent
172 | name @ sym::i8 | sym::u8 | sym::i16 | sym::u16 | sym::i32 | sym::u32 | sym::i64 |
sym::u64 | sym::i128 | sym::u128 | sym::isize | sym::usizeint_pat!(),
173 ),
174 ArgParser::List(_),
175 ) => {
176 cx.emit_err(session_diagnostics::InvalidReprHintNoParen { span: param.span(), name });
177 None
178 }
179
180 _ => {
181 cx.emit_err(session_diagnostics::UnrecognizedReprHint { span: param.span() });
182 None
183 }
184 }
185}
186
187enum AlignKind {
188 Packed,
189 Align,
190}
191
192fn parse_repr_align<S: Stage>(
193 cx: &AcceptContext<'_, '_, S>,
194 list: &MetaItemListParser,
195 param_span: Span,
196 align_kind: AlignKind,
197) -> Option<ReprAttr> {
198 use AlignKind::*;
199
200 let Some(align) = list.single() else {
201 match align_kind {
202 Packed => {
203 cx.emit_err(session_diagnostics::IncorrectReprFormatPackedOneOrZeroArg {
204 span: param_span,
205 });
206 }
207 Align => {
208 cx.emit_err(session_diagnostics::IncorrectReprFormatAlignOneArg {
209 span: param_span,
210 });
211 }
212 }
213
214 return None;
215 };
216
217 let Some(lit) = align.lit() else {
218 match align_kind {
219 Packed => {
220 cx.emit_err(session_diagnostics::IncorrectReprFormatPackedExpectInteger {
221 span: align.span(),
222 });
223 }
224 Align => {
225 cx.emit_err(session_diagnostics::IncorrectReprFormatExpectInteger {
226 span: align.span(),
227 });
228 }
229 }
230
231 return None;
232 };
233
234 match parse_alignment(&lit.kind, cx) {
235 Ok(literal) => Some(match align_kind {
236 AlignKind::Packed => ReprAttr::ReprPacked(literal),
237 AlignKind::Align => ReprAttr::ReprAlign(literal),
238 }),
239 Err(message) => {
240 cx.emit_err(session_diagnostics::InvalidReprGeneric {
241 span: lit.span,
242 repr_arg: match align_kind {
243 Packed => "packed".to_string(),
244 Align => "align".to_string(),
245 },
246 error_part: message,
247 });
248 None
249 }
250 }
251}
252
253fn parse_alignment<S: Stage>(
254 node: &LitKind,
255 cx: &AcceptContext<'_, '_, S>,
256) -> Result<Align, String> {
257 let LitKind::Int(literal, LitIntType::Unsuffixed) = node else {
258 return Err("not an unsuffixed integer".to_string());
259 };
260
261 if !literal.get().is_power_of_two() {
264 return Err("not a power of two".to_string());
265 }
266 let align = literal
268 .get()
269 .try_into()
270 .ok()
271 .and_then(|a| Align::from_bytes(a).ok())
272 .ok_or("larger than 2^29".to_string())?;
273
274 let max = Size::from_bits(cx.sess.target.pointer_width).signed_int_max() as u64;
276 if align.bytes() > max {
277 return Err(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("alignment larger than `isize::MAX` bytes ({0} for the current target)",
max))
})format!(
278 "alignment larger than `isize::MAX` bytes ({max} for the current target)"
279 ));
280 }
281 Ok(align)
282}
283
284#[derive(#[automatically_derived]
impl ::core::default::Default for RustcAlignParser {
#[inline]
fn default() -> RustcAlignParser {
RustcAlignParser(::core::default::Default::default())
}
}Default)]
286pub(crate) struct RustcAlignParser(Option<(Align, Span)>);
287
288impl RustcAlignParser {
289 const PATH: &[Symbol] = &[sym::rustc_align];
290 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: false,
list: Some(&["<alignment in bytes>"]),
one_of: &[],
name_value_str: None,
docs: None,
}template!(List: &["<alignment in bytes>"]);
291
292 fn parse<S: Stage>(&mut self, cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) {
293 match args {
294 ArgParser::NoArgs | ArgParser::NameValue(_) => {
295 let attr_span = cx.attr_span;
296 cx.adcx().expected_list(attr_span, args);
297 }
298 ArgParser::List(list) => {
299 let Some(align) = list.single() else {
300 cx.adcx().expected_single_argument(list.span);
301 return;
302 };
303
304 let Some(lit) = align.lit() else {
305 cx.emit_err(session_diagnostics::IncorrectReprFormatExpectInteger {
306 span: align.span(),
307 });
308
309 return;
310 };
311
312 match parse_alignment(&lit.kind, cx) {
313 Ok(literal) => self.0 = Ord::max(self.0, Some((literal, cx.attr_span))),
314 Err(message) => {
315 cx.emit_err(session_diagnostics::InvalidAlignmentValue {
316 span: lit.span,
317 error_part: message,
318 });
319 }
320 }
321 }
322 }
323 }
324}
325
326impl<S: Stage> AttributeParser<S> for RustcAlignParser {
327 const ATTRIBUTES: AcceptMapping<Self, S> = &[(Self::PATH, Self::TEMPLATE, Self::parse)];
328 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
329 Allow(Target::Fn),
330 Allow(Target::Method(MethodKind::Inherent)),
331 Allow(Target::Method(MethodKind::Trait { body: true })),
332 Allow(Target::Method(MethodKind::TraitImpl)),
333 Allow(Target::Method(MethodKind::Trait { body: false })), Allow(Target::ForeignFn),
335 ]);
336
337 fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
338 let (align, span) = self.0?;
339 Some(AttributeKind::RustcAlign { align, span })
340 }
341}
342
343#[derive(#[automatically_derived]
impl ::core::default::Default for RustcAlignStaticParser {
#[inline]
fn default() -> RustcAlignStaticParser {
RustcAlignStaticParser(::core::default::Default::default())
}
}Default)]
344pub(crate) struct RustcAlignStaticParser(RustcAlignParser);
345
346impl RustcAlignStaticParser {
347 const PATH: &[Symbol] = &[sym::rustc_align_static];
348 const TEMPLATE: AttributeTemplate = RustcAlignParser::TEMPLATE;
349
350 fn parse<S: Stage>(&mut self, cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) {
351 self.0.parse(cx, args)
352 }
353}
354
355impl<S: Stage> AttributeParser<S> for RustcAlignStaticParser {
356 const ATTRIBUTES: AcceptMapping<Self, S> = &[(Self::PATH, Self::TEMPLATE, Self::parse)];
357 const ALLOWED_TARGETS: AllowedTargets =
358 AllowedTargets::AllowList(&[Allow(Target::Static), Allow(Target::ForeignStatic)]);
359
360 fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
361 let (align, span) = self.0.0?;
362 Some(AttributeKind::RustcAlign { align, span })
363 }
364}