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