rustc_attr_parsing/attributes/
repr.rs1use rustc_abi::{Align, Size};
2use rustc_ast::{IntTy, LitIntType, LitKind, UintTy};
3use rustc_hir::attrs::IntType::{SignedInt, UnsignedInt};
4use rustc_hir::attrs::ReprAttr;
5
6use super::prelude::*;
7use crate::session_diagnostics;
8
9pub(crate) struct ReprParser;
19
20impl CombineAttributeParser for ReprParser {
21 type Item = (ReprAttr, Span);
22 const PATH: &[Symbol] = &[sym::repr];
23 const CONVERT: ConvertFn<Self::Item> =
24 |items, first_span| AttributeKind::Repr { reprs: items, first_span };
25 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!(
26 List: &["C", "Rust", "transparent", "align(...)", "packed(...)", "<integer type>"],
27 "https://doc.rust-lang.org/reference/type-layout.html#representations"
28 );
29
30 fn extend(
31 cx: &mut AcceptContext<'_, '_>,
32 args: &ArgParser,
33 ) -> impl IntoIterator<Item = Self::Item> {
34 let Some(list) = cx.expect_list(args, cx.attr_span) else {
35 return ::alloc::vec::Vec::new()vec![];
36 };
37
38 if list.is_empty() {
39 let attr_span = cx.attr_span;
40 cx.adcx().warn_empty_attribute(attr_span);
41 return ::alloc::vec::Vec::new()vec![];
42 }
43
44 let mut reprs = Vec::new();
45 for param in list.mixed() {
46 let Some(item) = param.meta_item() else {
47 cx.adcx().expected_identifier(param.span());
48 continue;
49 };
50 reprs.extend(parse_repr(cx, &item).map(|r| (r, param.span())));
51 }
52 reprs
53 }
54
55 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
58}
59
60fn parse_repr(cx: &mut AcceptContext<'_, '_>, param: &MetaItemParser) -> Option<ReprAttr> {
61 use ReprAttr::*;
62
63 macro_rules! no_args {
64 ($constructor: expr) => {{
65 cx.expect_no_args(param.args())?;
66 Some($constructor)
67 }};
68 }
69
70 match param.path().word_sym() {
71 Some(sym::align) => {
72 let l = cx.expect_list(param.args(), param.span())?;
73 parse_repr_align(cx, l, AlignKind::Align)
74 }
75 Some(sym::packed) => match param.args() {
76 ArgParser::NoArgs => Some(ReprPacked(Align::ONE)),
77 ArgParser::List(l) => parse_repr_align(cx, l, AlignKind::Packed),
78 ArgParser::NameValue(_) => {
79 cx.adcx().expected_list_or_no_args(param.span());
80 None
81 }
82 },
83 Some(sym::Rust) => { cx.expect_no_args(param.args())?; Some(ReprRust) }no_args!(ReprRust),
84 Some(sym::C) => { cx.expect_no_args(param.args())?; Some(ReprC) }no_args!(ReprC),
85 Some(sym::simd) => { cx.expect_no_args(param.args())?; Some(ReprSimd) }no_args!(ReprSimd),
86 Some(sym::transparent) => { cx.expect_no_args(param.args())?; Some(ReprTransparent) }no_args!(ReprTransparent),
87 Some(sym::i8) => { cx.expect_no_args(param.args())?; Some(ReprInt(SignedInt(IntTy::I8))) }no_args!(ReprInt(SignedInt(IntTy::I8))),
88 Some(sym::u8) => { cx.expect_no_args(param.args())?; Some(ReprInt(UnsignedInt(UintTy::U8))) }no_args!(ReprInt(UnsignedInt(UintTy::U8))),
89 Some(sym::i16) => { cx.expect_no_args(param.args())?; Some(ReprInt(SignedInt(IntTy::I16))) }no_args!(ReprInt(SignedInt(IntTy::I16))),
90 Some(sym::u16) => { cx.expect_no_args(param.args())?; Some(ReprInt(UnsignedInt(UintTy::U16))) }no_args!(ReprInt(UnsignedInt(UintTy::U16))),
91 Some(sym::i32) => { cx.expect_no_args(param.args())?; Some(ReprInt(SignedInt(IntTy::I32))) }no_args!(ReprInt(SignedInt(IntTy::I32))),
92 Some(sym::u32) => { cx.expect_no_args(param.args())?; Some(ReprInt(UnsignedInt(UintTy::U32))) }no_args!(ReprInt(UnsignedInt(UintTy::U32))),
93 Some(sym::i64) => { cx.expect_no_args(param.args())?; Some(ReprInt(SignedInt(IntTy::I64))) }no_args!(ReprInt(SignedInt(IntTy::I64))),
94 Some(sym::u64) => { cx.expect_no_args(param.args())?; Some(ReprInt(UnsignedInt(UintTy::U64))) }no_args!(ReprInt(UnsignedInt(UintTy::U64))),
95 Some(sym::i128) => { cx.expect_no_args(param.args())?; Some(ReprInt(SignedInt(IntTy::I128))) }no_args!(ReprInt(SignedInt(IntTy::I128))),
96 Some(sym::u128) => { cx.expect_no_args(param.args())?; Some(ReprInt(UnsignedInt(UintTy::U128))) }no_args!(ReprInt(UnsignedInt(UintTy::U128))),
97 Some(sym::isize) => { cx.expect_no_args(param.args())?; Some(ReprInt(SignedInt(IntTy::Isize))) }no_args!(ReprInt(SignedInt(IntTy::Isize))),
98 Some(sym::usize) => {
cx.expect_no_args(param.args())?;
Some(ReprInt(UnsignedInt(UintTy::Usize)))
}no_args!(ReprInt(UnsignedInt(UintTy::Usize))),
99 _ => {
100 cx.adcx().expected_specific_argument(
101 param.span(),
102 &[
103 sym::align,
104 sym::packed,
105 sym::Rust,
106 sym::C,
107 sym::simd,
108 sym::transparent,
109 sym::i8,
110 sym::u8,
111 sym::i16,
112 sym::u16,
113 sym::i32,
114 sym::u32,
115 sym::i64,
116 sym::u64,
117 sym::i128,
118 sym::u128,
119 sym::isize,
120 sym::usize,
121 ],
122 );
123 None
124 }
125 }
126}
127
128enum AlignKind {
129 Packed,
130 Align,
131}
132
133fn parse_repr_align(
134 cx: &mut AcceptContext<'_, '_>,
135 list: &MetaItemListParser,
136 align_kind: AlignKind,
137) -> Option<ReprAttr> {
138 let Some(align) = list.as_single() else {
139 cx.adcx().expected_single_argument(list.span, list.len());
140 return None;
141 };
142
143 let Some(lit) = align.as_lit() else {
144 cx.adcx().expected_integer_literal(align.span());
145 return None;
146 };
147
148 match parse_alignment(&lit.kind, cx) {
149 Ok(literal) => Some(match align_kind {
150 AlignKind::Packed => ReprAttr::ReprPacked(literal),
151 AlignKind::Align => ReprAttr::ReprAlign(literal),
152 }),
153 Err(message) => {
154 cx.emit_err(session_diagnostics::InvalidAlignmentValue {
155 span: lit.span,
156 error_part: message,
157 });
158 None
159 }
160 }
161}
162
163fn parse_alignment(node: &LitKind, cx: &AcceptContext<'_, '_>) -> Result<Align, String> {
164 let LitKind::Int(literal, LitIntType::Unsuffixed) = node else {
165 return Err("not an unsuffixed integer".to_string());
166 };
167
168 if !literal.get().is_power_of_two() {
171 return Err("not a power of two".to_string());
172 }
173 let align = literal
175 .get()
176 .try_into()
177 .ok()
178 .and_then(|a| Align::from_bytes(a).ok())
179 .ok_or("larger than 2^29".to_string())?;
180
181 let max = Size::from_bits(cx.sess.target.pointer_width).signed_int_max() as u64;
183 if align.bytes() > max {
184 return Err(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("alignment larger than `isize::MAX` bytes ({0} for the current target)",
max))
})format!(
185 "alignment larger than `isize::MAX` bytes ({max} for the current target)"
186 ));
187 }
188 Ok(align)
189}
190
191#[derive(#[automatically_derived]
impl ::core::default::Default for RustcAlignParser {
#[inline]
fn default() -> RustcAlignParser {
RustcAlignParser(::core::default::Default::default())
}
}Default)]
193pub(crate) struct RustcAlignParser(Option<(Align, Span)>);
194
195impl RustcAlignParser {
196 const PATH: &[Symbol] = &[sym::rustc_align];
197 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>"]);
198
199 fn parse(&mut self, cx: &mut AcceptContext<'_, '_>, args: &ArgParser) {
200 let Some(list) = cx.expect_list(args, cx.attr_span) else {
201 return;
202 };
203
204 let Some(align) = cx.expect_single(list) else {
205 return;
206 };
207
208 let Some(lit) = align.as_lit() else {
209 cx.adcx().expected_integer_literal(align.span());
210 return;
211 };
212
213 match parse_alignment(&lit.kind, cx) {
214 Ok(literal) => self.0 = Ord::max(self.0, Some((literal, cx.attr_span))),
215 Err(message) => {
216 cx.emit_err(session_diagnostics::InvalidAlignmentValue {
217 span: lit.span,
218 error_part: message,
219 });
220 }
221 }
222 }
223}
224
225impl AttributeParser for RustcAlignParser {
226 const ATTRIBUTES: AcceptMapping<Self> = &[(Self::PATH, Self::TEMPLATE, Self::parse)];
227 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
228 Allow(Target::Fn),
229 Allow(Target::Method(MethodKind::Inherent)),
230 Allow(Target::Method(MethodKind::Trait { body: true })),
231 Allow(Target::Method(MethodKind::TraitImpl)),
232 Allow(Target::Method(MethodKind::Trait { body: false })), Allow(Target::ForeignFn),
234 ]);
235
236 fn finalize(self, _cx: &FinalizeContext<'_, '_>) -> Option<AttributeKind> {
237 let (align, span) = self.0?;
238 Some(AttributeKind::RustcAlign { align, span })
239 }
240}
241
242#[derive(#[automatically_derived]
impl ::core::default::Default for RustcAlignStaticParser {
#[inline]
fn default() -> RustcAlignStaticParser {
RustcAlignStaticParser(::core::default::Default::default())
}
}Default)]
243pub(crate) struct RustcAlignStaticParser(RustcAlignParser);
244
245impl RustcAlignStaticParser {
246 const PATH: &[Symbol] = &[sym::rustc_align_static];
247 const TEMPLATE: AttributeTemplate = RustcAlignParser::TEMPLATE;
248
249 fn parse(&mut self, cx: &mut AcceptContext<'_, '_>, args: &ArgParser) {
250 self.0.parse(cx, args)
251 }
252}
253
254impl AttributeParser for RustcAlignStaticParser {
255 const ATTRIBUTES: AcceptMapping<Self> = &[(Self::PATH, Self::TEMPLATE, Self::parse)];
256 const ALLOWED_TARGETS: AllowedTargets =
257 AllowedTargets::AllowList(&[Allow(Target::Static), Allow(Target::ForeignStatic)]);
258
259 fn finalize(self, _cx: &FinalizeContext<'_, '_>) -> Option<AttributeKind> {
260 let (align, span) = self.0.0?;
261 Some(AttributeKind::RustcAlign { align, span })
262 }
263}