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