1use core::{
12 convert::{Infallible, TryFrom},
13 num::NonZeroU32,
14};
15
16use proc_macro2::{Span, TokenStream};
17use quote::{quote_spanned, ToTokens, TokenStreamExt as _};
18use syn::{
19 punctuated::Punctuated, spanned::Spanned as _, token::Comma, Attribute, Error, LitInt, Meta,
20 MetaList,
21};
22
23use crate::util::{path_is_ident, to_ident_str};
24
25#[cfg_attr(test, derive(Copy, Clone, Debug))]
31pub(crate) enum Repr<Prim, Packed> {
32 Transparent(Span),
34 Compound(Spanned<CompoundRepr<Prim>>, Option<Spanned<AlignRepr<Packed>>>),
37}
38
39#[cfg_attr(test, derive(Copy, Clone, Debug, Eq, PartialEq))]
41pub(crate) enum CompoundRepr<Prim> {
42 C,
43 Rust,
44 Primitive(Prim),
45}
46
47#[derive(Copy, Clone)]
49#[cfg_attr(test, derive(Debug, Eq, PartialEq))]
50pub(crate) enum PrimitiveRepr {
51 U8,
52 U16,
53 U32,
54 U64,
55 U128,
56 Usize,
57 I8,
58 I16,
59 I32,
60 I64,
61 I128,
62 Isize,
63}
64
65#[cfg_attr(test, derive(Copy, Clone, Debug, Eq, PartialEq))]
67pub(crate) enum AlignRepr<Packed> {
68 Packed(Packed),
69 Align(NonZeroU32),
70}
71
72pub(crate) type StructUnionRepr = Repr<Infallible, NonZeroU32>;
74
75pub(crate) type EnumRepr = Repr<PrimitiveRepr, Infallible>;
77
78impl<Prim, Packed> Repr<Prim, Packed> {
79 pub(crate) fn repr_type_name(&self) -> &str
85 where
86 Prim: Copy + With<PrimitiveRepr>,
87 {
88 use CompoundRepr::*;
89 use PrimitiveRepr::*;
90 use Repr::*;
91 match self {
92 Transparent(_span) => "repr(transparent)",
93 Compound(Spanned { t: repr, span: _ }, _align) => match repr {
94 C => "repr(C)",
95 Rust => "repr(Rust)",
96 Primitive(prim) => prim.with(|prim| match prim {
97 U8 => "repr(u8)",
98 U16 => "repr(u16)",
99 U32 => "repr(u32)",
100 U64 => "repr(u64)",
101 U128 => "repr(u128)",
102 Usize => "repr(usize)",
103 I8 => "repr(i8)",
104 I16 => "repr(i16)",
105 I32 => "repr(i32)",
106 I64 => "repr(i64)",
107 I128 => "repr(i128)",
108 Isize => "repr(isize)",
109 }),
110 },
111 }
112 }
113
114 pub(crate) fn is_transparent(&self) -> bool {
115 matches!(self, Repr::Transparent(_))
116 }
117
118 pub(crate) fn is_c(&self) -> bool {
119 use CompoundRepr::*;
120 matches!(self, Repr::Compound(Spanned { t: C, span: _ }, _align))
121 }
122
123 pub(crate) fn is_primitive(&self) -> bool {
124 use CompoundRepr::*;
125 matches!(self, Repr::Compound(Spanned { t: Primitive(_), span: _ }, _align))
126 }
127
128 pub(crate) fn get_packed(&self) -> Option<&Packed> {
129 use AlignRepr::*;
130 use Repr::*;
131 if let Compound(_, Some(Spanned { t: Packed(p), span: _ })) = self {
132 Some(p)
133 } else {
134 None
135 }
136 }
137
138 pub(crate) fn get_align(&self) -> Option<Spanned<NonZeroU32>> {
139 use AlignRepr::*;
140 use Repr::*;
141 if let Compound(_, Some(Spanned { t: Align(n), span })) = self {
142 Some(Spanned::new(*n, *span))
143 } else {
144 None
145 }
146 }
147
148 pub(crate) fn is_align_gt_1(&self) -> bool {
149 self.get_align().map(|n| n.t.get() > 1).unwrap_or(false)
150 }
151
152 pub(crate) fn unaligned_validate_no_align_gt_1(&self) -> Result<(), Error> {
157 if let Some(n) = self.get_align().filter(|n| n.t.get() > 1) {
158 Err(Error::new(
159 n.span,
160 "cannot derive `Unaligned` on type with alignment greater than 1",
161 ))
162 } else {
163 Ok(())
164 }
165 }
166}
167
168impl<Prim> Repr<Prim, NonZeroU32> {
169 pub(crate) fn is_packed_1(&self) -> bool {
171 self.get_packed().map(|n| n.get() == 1).unwrap_or(false)
172 }
173}
174
175impl<Packed> Repr<PrimitiveRepr, Packed> {
176 fn get_primitive(&self) -> Option<&PrimitiveRepr> {
177 use CompoundRepr::*;
178 use Repr::*;
179 if let Compound(Spanned { t: Primitive(p), span: _ }, _align) = self {
180 Some(p)
181 } else {
182 None
183 }
184 }
185
186 pub(crate) fn is_u8(&self) -> bool {
188 matches!(self.get_primitive(), Some(PrimitiveRepr::U8))
189 }
190
191 pub(crate) fn is_i8(&self) -> bool {
193 matches!(self.get_primitive(), Some(PrimitiveRepr::I8))
194 }
195}
196
197impl<Prim, Packed> ToTokens for Repr<Prim, Packed>
198where
199 Prim: With<PrimitiveRepr> + Copy,
200 Packed: With<NonZeroU32> + Copy,
201{
202 fn to_tokens(&self, ts: &mut TokenStream) {
203 use Repr::*;
204 match self {
205 Transparent(span) => ts.append_all(quote_spanned! { *span=> #[repr(transparent)] }),
206 Compound(repr, align) => {
207 repr.to_tokens(ts);
208 if let Some(align) = align {
209 align.to_tokens(ts);
210 }
211 }
212 }
213 }
214}
215
216impl<Prim: With<PrimitiveRepr> + Copy> ToTokens for Spanned<CompoundRepr<Prim>> {
217 fn to_tokens(&self, ts: &mut TokenStream) {
218 use CompoundRepr::*;
219 match &self.t {
220 C => ts.append_all(quote_spanned! { self.span=> #[repr(C)] }),
221 Rust => ts.append_all(quote_spanned! { self.span=> #[repr(Rust)] }),
222 Primitive(prim) => prim.with(|prim| Spanned::new(prim, self.span).to_tokens(ts)),
223 }
224 }
225}
226
227impl ToTokens for Spanned<PrimitiveRepr> {
228 fn to_tokens(&self, ts: &mut TokenStream) {
229 use PrimitiveRepr::*;
230 match self.t {
231 U8 => ts.append_all(quote_spanned! { self.span => #[repr(u8)] }),
232 U16 => ts.append_all(quote_spanned! { self.span => #[repr(u16)] }),
233 U32 => ts.append_all(quote_spanned! { self.span => #[repr(u32)] }),
234 U64 => ts.append_all(quote_spanned! { self.span => #[repr(u64)] }),
235 U128 => ts.append_all(quote_spanned! { self.span => #[repr(u128)] }),
236 Usize => ts.append_all(quote_spanned! { self.span => #[repr(usize)] }),
237 I8 => ts.append_all(quote_spanned! { self.span => #[repr(i8)] }),
238 I16 => ts.append_all(quote_spanned! { self.span => #[repr(i16)] }),
239 I32 => ts.append_all(quote_spanned! { self.span => #[repr(i32)] }),
240 I64 => ts.append_all(quote_spanned! { self.span => #[repr(i64)] }),
241 I128 => ts.append_all(quote_spanned! { self.span => #[repr(i128)] }),
242 Isize => ts.append_all(quote_spanned! { self.span => #[repr(isize)] }),
243 }
244 }
245}
246
247impl<Packed: With<NonZeroU32> + Copy> ToTokens for Spanned<AlignRepr<Packed>> {
248 fn to_tokens(&self, ts: &mut TokenStream) {
249 use AlignRepr::*;
250 let to_index = |n: NonZeroU32| syn::Index { index: n.get(), span: self.span };
255 match self.t {
256 Packed(n) => n.with(|n| {
257 let n = to_index(n);
258 ts.append_all(quote_spanned! { self.span => #[repr(packed(#n))] })
259 }),
260 Align(n) => {
261 let n = to_index(n);
262 ts.append_all(quote_spanned! { self.span => #[repr(align(#n))] })
263 }
264 }
265 }
266}
267
268#[derive(Copy, Clone, PartialEq, Eq)]
271#[cfg_attr(test, derive(Debug))]
272pub(crate) enum RawRepr {
273 Transparent,
274 C,
275 Rust,
276 U8,
277 U16,
278 U32,
279 U64,
280 U128,
281 Usize,
282 I8,
283 I16,
284 I32,
285 I64,
286 I128,
287 Isize,
288 Align(NonZeroU32),
289 PackedN(NonZeroU32),
290 Packed,
291}
292
293#[cfg_attr(test, derive(Debug, Eq, PartialEq))]
295pub(crate) enum FromRawReprError<E> {
296 None,
299 Err(E),
302}
303
304#[cfg_attr(test, derive(Copy, Clone, Debug, Eq, PartialEq))]
306pub(crate) struct UnsupportedReprError;
307
308impl<Prim: With<PrimitiveRepr>> TryFrom<RawRepr> for CompoundRepr<Prim> {
309 type Error = FromRawReprError<UnsupportedReprError>;
310 fn try_from(
311 raw: RawRepr,
312 ) -> Result<CompoundRepr<Prim>, FromRawReprError<UnsupportedReprError>> {
313 use RawRepr::*;
314 match raw {
315 C => Ok(CompoundRepr::C),
316 Rust => Ok(CompoundRepr::Rust),
317 raw @ (U8 | U16 | U32 | U64 | U128 | Usize | I8 | I16 | I32 | I64 | I128 | Isize) => {
318 Prim::try_with_or(
319 || match raw {
320 U8 => Ok(PrimitiveRepr::U8),
321 U16 => Ok(PrimitiveRepr::U16),
322 U32 => Ok(PrimitiveRepr::U32),
323 U64 => Ok(PrimitiveRepr::U64),
324 U128 => Ok(PrimitiveRepr::U128),
325 Usize => Ok(PrimitiveRepr::Usize),
326 I8 => Ok(PrimitiveRepr::I8),
327 I16 => Ok(PrimitiveRepr::I16),
328 I32 => Ok(PrimitiveRepr::I32),
329 I64 => Ok(PrimitiveRepr::I64),
330 I128 => Ok(PrimitiveRepr::I128),
331 Isize => Ok(PrimitiveRepr::Isize),
332 Transparent | C | Rust | Align(_) | PackedN(_) | Packed => {
333 Err(UnsupportedReprError)
334 }
335 },
336 UnsupportedReprError,
337 )
338 .map(CompoundRepr::Primitive)
339 .map_err(FromRawReprError::Err)
340 }
341 Transparent | Align(_) | PackedN(_) | Packed => Err(FromRawReprError::None),
342 }
343 }
344}
345
346impl<Pcked: With<NonZeroU32>> TryFrom<RawRepr> for AlignRepr<Pcked> {
347 type Error = FromRawReprError<UnsupportedReprError>;
348 fn try_from(raw: RawRepr) -> Result<AlignRepr<Pcked>, FromRawReprError<UnsupportedReprError>> {
349 use RawRepr::*;
350 match raw {
351 Packed | PackedN(_) => Pcked::try_with_or(
352 || match raw {
353 Packed => Ok(NonZeroU32::new(1).unwrap()),
354 PackedN(n) => Ok(n),
355 U8 | U16 | U32 | U64 | U128 | Usize | I8 | I16 | I32 | I64 | I128 | Isize
356 | Transparent | C | Rust | Align(_) => Err(UnsupportedReprError),
357 },
358 UnsupportedReprError,
359 )
360 .map(AlignRepr::Packed)
361 .map_err(FromRawReprError::Err),
362 Align(n) => Ok(AlignRepr::Align(n)),
363 U8 | U16 | U32 | U64 | U128 | Usize | I8 | I16 | I32 | I64 | I128 | Isize
364 | Transparent | C | Rust => Err(FromRawReprError::None),
365 }
366 }
367}
368
369#[cfg_attr(test, derive(Copy, Clone, Debug, Eq, PartialEq))]
371enum FromRawReprsError<E> {
372 Single(E),
376 Conflict,
381}
382
383fn try_from_raw_reprs<'a, E, R: TryFrom<RawRepr, Error = FromRawReprError<E>>>(
385 r: impl IntoIterator<Item = &'a Spanned<RawRepr>>,
386) -> Result<Option<Spanned<R>>, Spanned<FromRawReprsError<E>>> {
387 r.into_iter().try_fold(None, |found: Option<Spanned<R>>, raw| {
391 let new = match Spanned::<R>::try_from(*raw) {
392 Ok(r) => r,
393 Err(FromRawReprError::None) => return Ok(found),
396 Err(FromRawReprError::Err(Spanned { t: err, span })) => {
399 return Err(Spanned::new(FromRawReprsError::Single(err), span))
400 }
401 };
402
403 if let Some(found) = found {
404 let span = found.span.join(new.span).unwrap_or(new.span);
411 Err(Spanned::new(FromRawReprsError::Conflict, span))
412 } else {
413 Ok(Some(new))
414 }
415 })
416}
417
418#[cfg_attr(test, derive(Copy, Clone, Debug, Eq, PartialEq))]
420enum FromAttrsError {
421 FromRawReprs(FromRawReprsError<UnsupportedReprError>),
422 Unrecognized,
423}
424
425impl From<FromRawReprsError<UnsupportedReprError>> for FromAttrsError {
426 fn from(err: FromRawReprsError<UnsupportedReprError>) -> FromAttrsError {
427 FromAttrsError::FromRawReprs(err)
428 }
429}
430
431impl From<UnrecognizedReprError> for FromAttrsError {
432 fn from(_err: UnrecognizedReprError) -> FromAttrsError {
433 FromAttrsError::Unrecognized
434 }
435}
436
437impl From<Spanned<FromAttrsError>> for Error {
438 fn from(err: Spanned<FromAttrsError>) -> Error {
439 let Spanned { t: err, span } = err;
440 match err {
441 FromAttrsError::FromRawReprs(FromRawReprsError::Single(
442 _err @ UnsupportedReprError,
443 )) => Error::new(span, "unsupported representation hint for the decorated type"),
444 FromAttrsError::FromRawReprs(FromRawReprsError::Conflict) => {
445 Error::new(span, "this conflicts with another representation hint")
451 }
452 FromAttrsError::Unrecognized => Error::new(span, "unrecognized representation hint"),
453 }
454 }
455}
456
457impl<Prim, Packed> Repr<Prim, Packed> {
458 fn from_attrs_inner(attrs: &[Attribute]) -> Result<Repr<Prim, Packed>, Spanned<FromAttrsError>>
459 where
460 Prim: With<PrimitiveRepr>,
461 Packed: With<NonZeroU32>,
462 {
463 let raw_reprs = RawRepr::from_attrs(attrs).map_err(Spanned::from)?;
464
465 let transparent = {
466 let mut transparents = raw_reprs.iter().filter_map(|Spanned { t, span }| match t {
467 RawRepr::Transparent => Some(span),
468 _ => None,
469 });
470 let first = transparents.next();
471 let second = transparents.next();
472 match (first, second) {
473 (None, None) => None,
474 (Some(span), None) => Some(*span),
475 (Some(_), Some(second)) => {
476 return Err(Spanned::new(
477 FromAttrsError::FromRawReprs(FromRawReprsError::Conflict),
478 *second,
479 ))
480 }
481 (None, Some(_)) => unreachable!(),
484 }
485 };
486
487 let compound: Option<Spanned<CompoundRepr<Prim>>> =
488 try_from_raw_reprs(raw_reprs.iter()).map_err(Spanned::from)?;
489 let align: Option<Spanned<AlignRepr<Packed>>> =
490 try_from_raw_reprs(raw_reprs.iter()).map_err(Spanned::from)?;
491
492 if let Some(span) = transparent {
493 if compound.is_some() || align.is_some() {
494 return Err(Spanned::new(FromRawReprsError::Conflict.into(), span));
497 }
498
499 Ok(Repr::Transparent(span))
500 } else {
501 Ok(Repr::Compound(
502 compound.unwrap_or(Spanned::new(CompoundRepr::Rust, Span::call_site())),
503 align,
504 ))
505 }
506 }
507}
508
509impl<Prim, Packed> Repr<Prim, Packed> {
510 pub(crate) fn from_attrs(attrs: &[Attribute]) -> Result<Repr<Prim, Packed>, Error>
511 where
512 Prim: With<PrimitiveRepr>,
513 Packed: With<NonZeroU32>,
514 {
515 Repr::from_attrs_inner(attrs).map_err(Into::into)
516 }
517}
518
519struct UnrecognizedReprError;
521
522impl RawRepr {
523 fn from_attrs(
524 attrs: &[Attribute],
525 ) -> Result<Vec<Spanned<RawRepr>>, Spanned<UnrecognizedReprError>> {
526 let mut reprs = Vec::new();
527 for attr in attrs {
528 if path_is_ident(attr.path(), "doc") {
530 continue;
531 }
532 if let Meta::List(ref meta_list) = attr.meta {
533 if path_is_ident(&meta_list.path, "repr") {
534 let parsed: Punctuated<Meta, Comma> =
535 match meta_list.parse_args_with(Punctuated::parse_terminated) {
536 Ok(parsed) => parsed,
537 Err(_) => {
538 return Err(Spanned::new(
539 UnrecognizedReprError,
540 meta_list.tokens.span(),
541 ))
542 }
543 };
544 for meta in parsed {
545 let s = meta.span();
546 reprs.push(
547 RawRepr::from_meta(&meta)
548 .map(|r| Spanned::new(r, s))
549 .map_err(|e| Spanned::new(e, s))?,
550 );
551 }
552 }
553 }
554 }
555
556 Ok(reprs)
557 }
558
559 fn from_meta(meta: &Meta) -> Result<RawRepr, UnrecognizedReprError> {
560 let (path, list) = match meta {
561 Meta::Path(path) => (path, None),
562 Meta::List(list) => (&list.path, Some(list)),
563 _ => return Err(UnrecognizedReprError),
564 };
565
566 let ident = path.get_ident().ok_or(UnrecognizedReprError)?;
567
568 #[allow(clippy::needless_nonzero_get)]
571 let parse_nzu64 = |list: &MetaList| {
572 list.parse_args::<LitInt>()
573 .and_then(|int| int.base10_parse::<NonZeroU32>())
574 .map_err(|_| UnrecognizedReprError)
575 .and_then(|nz| {
576 if nz.get().is_power_of_two() {
577 Ok(nz)
578 } else {
579 Err(UnrecognizedReprError)
580 }
581 })
582 };
583
584 use RawRepr::*;
585 let ident = to_ident_str(ident);
586 Ok(match (ident.as_str(), list) {
587 ("u8", None) => U8,
588 ("u16", None) => U16,
589 ("u32", None) => U32,
590 ("u64", None) => U64,
591 ("u128", None) => U128,
592 ("usize", None) => Usize,
593 ("i8", None) => I8,
594 ("i16", None) => I16,
595 ("i32", None) => I32,
596 ("i64", None) => I64,
597 ("i128", None) => I128,
598 ("isize", None) => Isize,
599 ("C", None) => C,
600 ("transparent", None) => Transparent,
601 ("Rust", None) => Rust,
602 ("packed", None) => Packed,
603 ("packed", Some(list)) => PackedN(parse_nzu64(list)?),
604 ("align", Some(list)) => Align(parse_nzu64(list)?),
605 _ => return Err(UnrecognizedReprError),
606 })
607 }
608}
609
610pub(crate) use util::*;
611mod util {
612 use super::*;
613 #[derive(Copy, Clone)]
615 #[cfg_attr(test, derive(Debug))]
616 pub(crate) struct Spanned<T> {
617 pub(crate) t: T,
618 pub(crate) span: Span,
619 }
620
621 impl<T> Spanned<T> {
622 pub(super) fn new(t: T, span: Span) -> Spanned<T> {
623 Spanned { t, span }
624 }
625
626 pub(super) fn from<U>(s: Spanned<U>) -> Spanned<T>
627 where
628 T: From<U>,
629 {
630 let Spanned { t: u, span } = s;
631 Spanned::new(u.into(), span)
632 }
633
634 pub(super) fn try_from<E, U>(
637 u: Spanned<U>,
638 ) -> Result<Spanned<T>, FromRawReprError<Spanned<E>>>
639 where
640 T: TryFrom<U, Error = FromRawReprError<E>>,
641 {
642 let Spanned { t: u, span } = u;
643 T::try_from(u).map(|t| Spanned { t, span }).map_err(|err| match err {
644 FromRawReprError::None => FromRawReprError::None,
645 FromRawReprError::Err(e) => FromRawReprError::Err(Spanned::new(e, span)),
646 })
647 }
648 }
649
650 pub(crate) trait Inhabited {}
653 impl Inhabited for PrimitiveRepr {}
654 impl Inhabited for NonZeroU32 {}
655
656 pub(crate) trait With<T> {
657 fn with<O, F: FnOnce(T) -> O>(self, f: F) -> O;
658 fn try_with_or<E, F: FnOnce() -> Result<T, E>>(f: F, err: E) -> Result<Self, E>
659 where
660 Self: Sized;
661 }
662
663 impl<T: Inhabited> With<T> for T {
664 fn with<O, F: FnOnce(T) -> O>(self, f: F) -> O {
665 f(self)
666 }
667
668 fn try_with_or<E, F: FnOnce() -> Result<T, E>>(f: F, _err: E) -> Result<Self, E> {
669 f()
670 }
671 }
672
673 impl<T> With<T> for Infallible {
674 fn with<O, F: FnOnce(T) -> O>(self, _f: F) -> O {
675 match self {}
676 }
677
678 fn try_with_or<E, F: FnOnce() -> Result<T, E>>(_f: F, err: E) -> Result<Self, E> {
679 Err(err)
680 }
681 }
682}
683
684#[cfg(test)]
685mod tests {
686 use syn::parse_quote;
687
688 use super::*;
689
690 impl<T> From<T> for Spanned<T> {
691 fn from(t: T) -> Spanned<T> {
692 Spanned::new(t, Span::call_site())
693 }
694 }
695
696 impl<T: PartialEq> PartialEq for Spanned<T> {
699 fn eq(&self, other: &Spanned<T>) -> bool {
700 self.t.eq(&other.t)
701 }
702 }
703
704 impl<T: Eq> Eq for Spanned<T> {}
705
706 impl<Prim: PartialEq, Packed: PartialEq> PartialEq for Repr<Prim, Packed> {
707 fn eq(&self, other: &Repr<Prim, Packed>) -> bool {
708 match (self, other) {
709 (Repr::Transparent(_), Repr::Transparent(_)) => true,
710 (Repr::Compound(sc, sa), Repr::Compound(oc, oa)) => (sc, sa) == (oc, oa),
711 _ => false,
712 }
713 }
714 }
715
716 fn s() -> Span {
717 Span::call_site()
718 }
719
720 #[test]
721 fn test() {
722 macro_rules! test {
725 ($(#[$attr:meta])* => $repr:expr) => {
726 test!(@inner $(#[$attr])* => Repr => Ok($repr));
727 };
728 (@error $(#[$attr:meta])* => $typ:ident => $repr:expr) => {
731 test!(@inner $(#[$attr])* => $typ => Err($repr));
732 };
733 (@inner $(#[$attr:meta])* => $typ:ident => $repr:expr) => {
734 let attr: Attribute = parse_quote!($(#[$attr])*);
735 let mut got = $typ::from_attrs_inner(&[attr]);
736 let expect: Result<Repr<_, _>, _> = $repr;
737 if false {
738 got = expect;
741 }
742 assert_eq!(got, expect, stringify!($(#[$attr])*));
743 };
744 }
745
746 use AlignRepr::*;
747 use CompoundRepr::*;
748 use PrimitiveRepr::*;
749 let nz = |n: u32| NonZeroU32::new(n).unwrap();
750
751 macro_rules! test_raw_repr {
756 ($ordinary:meta, $raw:meta => $expected:expr) => {{
757 let ordinary: Meta = parse_quote!($ordinary);
758 let raw: Meta = parse_quote!($raw);
759 assert_eq!(RawRepr::from_meta(&ordinary).ok().unwrap(), $expected);
760 assert_eq!(RawRepr::from_meta(&raw).ok().unwrap(), $expected);
761 }};
762 }
763
764 test_raw_repr!(transparent, r#transparent => RawRepr::Transparent);
765 test_raw_repr!(C, r#C => RawRepr::C);
766 test_raw_repr!(Rust, r#Rust => RawRepr::Rust);
767 test_raw_repr!(u8, r#u8 => RawRepr::U8);
768 test_raw_repr!(u16, r#u16 => RawRepr::U16);
769 test_raw_repr!(u32, r#u32 => RawRepr::U32);
770 test_raw_repr!(u64, r#u64 => RawRepr::U64);
771 test_raw_repr!(u128, r#u128 => RawRepr::U128);
772 test_raw_repr!(usize, r#usize => RawRepr::Usize);
773 test_raw_repr!(i8, r#i8 => RawRepr::I8);
774 test_raw_repr!(i16, r#i16 => RawRepr::I16);
775 test_raw_repr!(i32, r#i32 => RawRepr::I32);
776 test_raw_repr!(i64, r#i64 => RawRepr::I64);
777 test_raw_repr!(i128, r#i128 => RawRepr::I128);
778 test_raw_repr!(isize, r#isize => RawRepr::Isize);
779 test_raw_repr!(align(2), r#align(2) => RawRepr::Align(nz(2)));
780 test_raw_repr!(packed, r#packed => RawRepr::Packed);
781 test_raw_repr!(packed(2), r#packed(2) => RawRepr::PackedN(nz(2)));
782
783 test!(#[repr(transparent)] => StructUnionRepr::Transparent(s()));
784 test!(#[r#repr(r#transparent)] => StructUnionRepr::Transparent(s()));
785 test!(#[repr()] => StructUnionRepr::Compound(Rust.into(), None));
786 test!(#[repr(packed)] => StructUnionRepr::Compound(Rust.into(), Some(Packed(nz(1)).into())));
787 test!(#[repr(packed(2))] => StructUnionRepr::Compound(Rust.into(), Some(Packed(nz(2)).into())));
788 test!(#[repr(align(1))] => StructUnionRepr::Compound(Rust.into(), Some(Align(nz(1)).into())));
789 test!(#[repr(align(2))] => StructUnionRepr::Compound(Rust.into(), Some(Align(nz(2)).into())));
790 test!(#[repr(C)] => StructUnionRepr::Compound(C.into(), None));
791 test!(#[repr(C, packed)] => StructUnionRepr::Compound(C.into(), Some(Packed(nz(1)).into())));
792 test!(#[repr(C, packed(2))] => StructUnionRepr::Compound(C.into(), Some(Packed(nz(2)).into())));
793 test!(#[repr(C, align(1))] => StructUnionRepr::Compound(C.into(), Some(Align(nz(1)).into())));
794 test!(#[repr(C, align(2))] => StructUnionRepr::Compound(C.into(), Some(Align(nz(2)).into())));
795 test!(#[r#repr(r#C, r#align(2))] => StructUnionRepr::Compound(C.into(), Some(Align(nz(2)).into())));
796 test!(#[r#repr(r#C, r#packed(2))] => StructUnionRepr::Compound(C.into(), Some(Packed(nz(2)).into())));
797
798 test!(#[repr(transparent)] => EnumRepr::Transparent(s()));
799 test!(#[repr()] => EnumRepr::Compound(Rust.into(), None));
800 test!(#[repr(align(1))] => EnumRepr::Compound(Rust.into(), Some(Align(nz(1)).into())));
801 test!(#[repr(align(2))] => EnumRepr::Compound(Rust.into(), Some(Align(nz(2)).into())));
802
803 macro_rules! for_each_compound_repr {
804 ($($r:tt => $var:expr),*) => {
805 $(
806 test!(#[repr($r)] => EnumRepr::Compound($var.into(), None));
807 test!(#[repr($r, align(1))] => EnumRepr::Compound($var.into(), Some(Align(nz(1)).into())));
808 test!(#[repr($r, align(2))] => EnumRepr::Compound($var.into(), Some(Align(nz(2)).into())));
809 )*
810 }
811 }
812
813 for_each_compound_repr!(
814 C => C,
815 u8 => Primitive(U8),
816 u16 => Primitive(U16),
817 u32 => Primitive(U32),
818 u64 => Primitive(U64),
819 usize => Primitive(Usize),
820 i8 => Primitive(I8),
821 i16 => Primitive(I16),
822 i32 => Primitive(I32),
823 i64 => Primitive(I64),
824 isize => Primitive(Isize)
825 );
826
827 use FromAttrsError::*;
828 use FromRawReprsError::*;
829
830 macro_rules! for_each_repr_type {
833 ($($repr:ident),*) => {
834 $(
835 test!(@error #[repr(packed(0))] => $repr => Unrecognized.into());
837 test!(@error #[repr(packed(3))] => $repr => Unrecognized.into());
838 test!(@error #[repr(align(0))] => $repr => Unrecognized.into());
839 test!(@error #[repr(align(3))] => $repr => Unrecognized.into());
840
841 test!(@error #[repr(transparent, transparent)] => $repr => FromRawReprs(Conflict).into());
843 test!(@error #[repr(transparent, C)] => $repr => FromRawReprs(Conflict).into());
844 test!(@error #[repr(transparent, Rust)] => $repr => FromRawReprs(Conflict).into());
845
846 test!(@error #[repr(C, transparent)] => $repr => FromRawReprs(Conflict).into());
847 test!(@error #[repr(C, C)] => $repr => FromRawReprs(Conflict).into());
848 test!(@error #[repr(C, Rust)] => $repr => FromRawReprs(Conflict).into());
849
850 test!(@error #[repr(Rust, transparent)] => $repr => FromRawReprs(Conflict).into());
851 test!(@error #[repr(Rust, C)] => $repr => FromRawReprs(Conflict).into());
852 test!(@error #[repr(Rust, Rust)] => $repr => FromRawReprs(Conflict).into());
853 )*
854 }
855 }
856
857 for_each_repr_type!(StructUnionRepr, EnumRepr);
858
859 test!(@error #[repr(transparent, u8)] => EnumRepr => FromRawReprs(Conflict).into());
867 test!(@error #[repr(u8, transparent)] => EnumRepr => FromRawReprs(Conflict).into());
868 test!(@error #[repr(C, u8)] => EnumRepr => FromRawReprs(Conflict).into());
869 test!(@error #[repr(u8, C)] => EnumRepr => FromRawReprs(Conflict).into());
870 test!(@error #[repr(Rust, u8)] => EnumRepr => FromRawReprs(Conflict).into());
871 test!(@error #[repr(u8, Rust)] => EnumRepr => FromRawReprs(Conflict).into());
872 test!(@error #[repr(u8, u8)] => EnumRepr => FromRawReprs(Conflict).into());
873
874 test!(@error #[repr(u8)] => StructUnionRepr => FromRawReprs(Single(UnsupportedReprError)).into());
876 test!(@error #[repr(u16)] => StructUnionRepr => FromRawReprs(Single(UnsupportedReprError)).into());
877 test!(@error #[repr(u32)] => StructUnionRepr => FromRawReprs(Single(UnsupportedReprError)).into());
878 test!(@error #[repr(u64)] => StructUnionRepr => FromRawReprs(Single(UnsupportedReprError)).into());
879 test!(@error #[repr(usize)] => StructUnionRepr => FromRawReprs(Single(UnsupportedReprError)).into());
880 test!(@error #[repr(i8)] => StructUnionRepr => FromRawReprs(Single(UnsupportedReprError)).into());
881 test!(@error #[repr(i16)] => StructUnionRepr => FromRawReprs(Single(UnsupportedReprError)).into());
882 test!(@error #[repr(i32)] => StructUnionRepr => FromRawReprs(Single(UnsupportedReprError)).into());
883 test!(@error #[repr(i64)] => StructUnionRepr => FromRawReprs(Single(UnsupportedReprError)).into());
884 test!(@error #[repr(isize)] => StructUnionRepr => FromRawReprs(Single(UnsupportedReprError)).into());
885
886 test!(@error #[repr(packed)] => EnumRepr => FromRawReprs(Single(UnsupportedReprError)).into());
888 test!(@error #[repr(packed(1))] => EnumRepr => FromRawReprs(Single(UnsupportedReprError)).into());
889 test!(@error #[repr(packed(2))] => EnumRepr => FromRawReprs(Single(UnsupportedReprError)).into());
890 }
891}