rustc_attr_parsing/attributes/
repr.rs
1use rustc_abi::Align;
4use rustc_ast::attr::AttributeExt;
5use rustc_ast::{self as ast, MetaItemKind};
6use rustc_attr_data_structures::IntType;
7use rustc_attr_data_structures::ReprAttr::*;
8use rustc_session::Session;
9use rustc_span::{Symbol, sym};
10
11use crate::ReprAttr;
12use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause};
13
14pub fn find_repr_attrs(sess: &Session, attr: &impl AttributeExt) -> Vec<ReprAttr> {
22 if attr.has_name(sym::repr) { parse_repr_attr(sess, attr) } else { Vec::new() }
23}
24
25pub fn parse_repr_attr(sess: &Session, attr: &impl AttributeExt) -> Vec<ReprAttr> {
26 assert!(attr.has_name(sym::repr), "expected `#[repr(..)]`, found: {attr:?}");
27 let mut acc = Vec::new();
28 let dcx = sess.dcx();
29
30 if let Some(items) = attr.meta_item_list() {
31 for item in items {
32 let mut recognised = false;
33 if item.is_word() {
34 let hint = match item.name_or_empty() {
35 sym::Rust => Some(ReprRust),
36 sym::C => Some(ReprC),
37 sym::packed => Some(ReprPacked(Align::ONE)),
38 sym::simd => Some(ReprSimd),
39 sym::transparent => Some(ReprTransparent),
40 sym::align => {
41 sess.dcx().emit_err(session_diagnostics::InvalidReprAlignNeedArg {
42 span: item.span(),
43 });
44 recognised = true;
45 None
46 }
47 name => int_type_of_word(name).map(ReprInt),
48 };
49
50 if let Some(h) = hint {
51 recognised = true;
52 acc.push(h);
53 }
54 } else if let Some((name, value)) = item.singleton_lit_list() {
55 let mut literal_error = None;
56 let mut err_span = item.span();
57 if name == sym::align {
58 recognised = true;
59 match parse_alignment(&value.kind) {
60 Ok(literal) => acc.push(ReprAlign(literal)),
61 Err(message) => {
62 err_span = value.span;
63 literal_error = Some(message)
64 }
65 };
66 } else if name == sym::packed {
67 recognised = true;
68 match parse_alignment(&value.kind) {
69 Ok(literal) => acc.push(ReprPacked(literal)),
70 Err(message) => {
71 err_span = value.span;
72 literal_error = Some(message)
73 }
74 };
75 } else if matches!(name, sym::Rust | sym::C | sym::simd | sym::transparent)
76 || int_type_of_word(name).is_some()
77 {
78 recognised = true;
79 sess.dcx().emit_err(session_diagnostics::InvalidReprHintNoParen {
80 span: item.span(),
81 name: name.to_ident_string(),
82 });
83 }
84 if let Some(literal_error) = literal_error {
85 sess.dcx().emit_err(session_diagnostics::InvalidReprGeneric {
86 span: err_span,
87 repr_arg: name.to_ident_string(),
88 error_part: literal_error,
89 });
90 }
91 } else if let Some(meta_item) = item.meta_item() {
92 match &meta_item.kind {
93 MetaItemKind::NameValue(value) => {
94 if meta_item.has_name(sym::align) || meta_item.has_name(sym::packed) {
95 let name = meta_item.name_or_empty().to_ident_string();
96 recognised = true;
97 sess.dcx().emit_err(session_diagnostics::IncorrectReprFormatGeneric {
98 span: item.span(),
99 repr_arg: &name,
100 cause: IncorrectReprFormatGenericCause::from_lit_kind(
101 item.span(),
102 &value.kind,
103 &name,
104 ),
105 });
106 } else if matches!(
107 meta_item.name_or_empty(),
108 sym::Rust | sym::C | sym::simd | sym::transparent
109 ) || int_type_of_word(meta_item.name_or_empty()).is_some()
110 {
111 recognised = true;
112 sess.dcx().emit_err(session_diagnostics::InvalidReprHintNoValue {
113 span: meta_item.span,
114 name: meta_item.name_or_empty().to_ident_string(),
115 });
116 }
117 }
118 MetaItemKind::List(nested_items) => {
119 if meta_item.has_name(sym::align) {
120 recognised = true;
121 if let [nested_item] = nested_items.as_slice() {
122 sess.dcx().emit_err(
123 session_diagnostics::IncorrectReprFormatExpectInteger {
124 span: nested_item.span(),
125 },
126 );
127 } else {
128 sess.dcx().emit_err(
129 session_diagnostics::IncorrectReprFormatAlignOneArg {
130 span: meta_item.span,
131 },
132 );
133 }
134 } else if meta_item.has_name(sym::packed) {
135 recognised = true;
136 if let [nested_item] = nested_items.as_slice() {
137 sess.dcx().emit_err(
138 session_diagnostics::IncorrectReprFormatPackedExpectInteger {
139 span: nested_item.span(),
140 },
141 );
142 } else {
143 sess.dcx().emit_err(
144 session_diagnostics::IncorrectReprFormatPackedOneOrZeroArg {
145 span: meta_item.span,
146 },
147 );
148 }
149 } else if matches!(
150 meta_item.name_or_empty(),
151 sym::Rust | sym::C | sym::simd | sym::transparent
152 ) || int_type_of_word(meta_item.name_or_empty()).is_some()
153 {
154 recognised = true;
155 sess.dcx().emit_err(session_diagnostics::InvalidReprHintNoParen {
156 span: meta_item.span,
157 name: meta_item.name_or_empty().to_ident_string(),
158 });
159 }
160 }
161 _ => (),
162 }
163 }
164 if !recognised {
165 if sess.opts.pretty.is_none_or(|pp| pp.needs_analysis()) {
170 dcx.span_delayed_bug(item.span(), "unrecognized representation hint");
171 }
172 }
173 }
174 }
175 acc
176}
177
178fn int_type_of_word(s: Symbol) -> Option<IntType> {
179 use rustc_attr_data_structures::IntType::*;
180
181 match s {
182 sym::i8 => Some(SignedInt(ast::IntTy::I8)),
183 sym::u8 => Some(UnsignedInt(ast::UintTy::U8)),
184 sym::i16 => Some(SignedInt(ast::IntTy::I16)),
185 sym::u16 => Some(UnsignedInt(ast::UintTy::U16)),
186 sym::i32 => Some(SignedInt(ast::IntTy::I32)),
187 sym::u32 => Some(UnsignedInt(ast::UintTy::U32)),
188 sym::i64 => Some(SignedInt(ast::IntTy::I64)),
189 sym::u64 => Some(UnsignedInt(ast::UintTy::U64)),
190 sym::i128 => Some(SignedInt(ast::IntTy::I128)),
191 sym::u128 => Some(UnsignedInt(ast::UintTy::U128)),
192 sym::isize => Some(SignedInt(ast::IntTy::Isize)),
193 sym::usize => Some(UnsignedInt(ast::UintTy::Usize)),
194 _ => None,
195 }
196}
197
198pub fn parse_alignment(node: &ast::LitKind) -> Result<Align, &'static str> {
199 if let ast::LitKind::Int(literal, ast::LitIntType::Unsuffixed) = node {
200 if literal.get().is_power_of_two() {
202 literal
204 .get()
205 .try_into()
206 .ok()
207 .and_then(|v| Align::from_bytes(v).ok())
208 .ok_or("larger than 2^29")
209 } else {
210 Err("not a power of two")
211 }
212 } else {
213 Err("not an unsuffixed integer")
214 }
215}