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