1use alloc::string::String;
2
3use super::Capabilities;
4use crate::{arena::Handle, proc::Alignment};
5
6bitflags::bitflags! {
7 #[cfg_attr(feature = "serialize", derive(serde::Serialize))]
12 #[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
13 #[repr(transparent)]
14 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
15 pub struct TypeFlags: u8 {
16 const DATA = 0x1;
28
29 const SIZED = 0x2;
43
44 const COPY = 0x4;
46
47 const IO_SHAREABLE = 0x8;
55
56 const HOST_SHAREABLE = 0x10;
58
59 const CREATION_RESOLVED = 0x20;
62
63 const ARGUMENT = 0x40;
65
66 const CONSTRUCTIBLE = 0x80;
74 }
75}
76
77#[derive(Clone, Copy, Debug, thiserror::Error)]
78#[cfg_attr(test, derive(PartialEq))]
79pub enum Disalignment {
80 #[error("The array stride {stride} is not a multiple of the required alignment {alignment}")]
81 ArrayStride { stride: u32, alignment: Alignment },
82 #[error("The struct span {span}, is not a multiple of the required alignment {alignment}")]
83 StructSpan { span: u32, alignment: Alignment },
84 #[error("The struct member[{index}] offset {offset} is not a multiple of the required alignment {alignment}")]
85 MemberOffset {
86 index: u32,
87 offset: u32,
88 alignment: Alignment,
89 },
90 #[error("The struct member[{index}] offset {offset} must be at least {expected}")]
91 MemberOffsetAfterStruct {
92 index: u32,
93 offset: u32,
94 expected: u32,
95 },
96 #[error("The struct member[{index}] is not statically sized")]
97 UnsizedMember { index: u32 },
98 #[error("The type is not host-shareable")]
99 NonHostShareable,
100}
101
102#[derive(Clone, Debug, thiserror::Error)]
103#[cfg_attr(test, derive(PartialEq))]
104pub enum TypeError {
105 #[error("Capability {0:?} is required")]
106 MissingCapability(Capabilities),
107 #[error("The {0:?} scalar width {1} is not supported for an atomic")]
108 InvalidAtomicWidth(crate::ScalarKind, crate::Bytes),
109 #[error("Invalid type for pointer target {0:?}")]
110 InvalidPointerBase(Handle<crate::Type>),
111 #[error("Unsized types like {base:?} must be in the `Storage` address space, not `{space:?}`")]
112 InvalidPointerToUnsized {
113 base: Handle<crate::Type>,
114 space: crate::AddressSpace,
115 },
116 #[error("Expected data type, found {0:?}")]
117 InvalidData(Handle<crate::Type>),
118 #[error("Base type {0:?} for the array is invalid")]
119 InvalidArrayBaseType(Handle<crate::Type>),
120 #[error("Matrix elements must always be floating-point types")]
121 MatrixElementNotFloat,
122 #[error("The constant {0:?} is specialized, and cannot be used as an array size")]
123 UnsupportedSpecializedArrayLength(Handle<crate::Constant>),
124 #[error("{} of dimensionality {dim:?} and class {class:?} are not supported", if *.arrayed {"Arrayed images"} else {"Images"})]
125 UnsupportedImageType {
126 dim: crate::ImageDimension,
127 arrayed: bool,
128 class: crate::ImageClass,
129 },
130 #[error("Array stride {stride} does not match the expected {expected}")]
131 InvalidArrayStride { stride: u32, expected: u32 },
132 #[error("Field '{0}' can't be dynamically-sized, has type {1:?}")]
133 InvalidDynamicArray(String, Handle<crate::Type>),
134 #[error("The base handle {0:?} has to be a struct")]
135 BindingArrayBaseTypeNotStruct(Handle<crate::Type>),
136 #[error("Binding arrays of external textures are not yet supported")]
137 BindingArrayBaseExternalTextures,
138 #[error("Structure member[{index}] at {offset} overlaps the previous member")]
139 MemberOverlap { index: u32, offset: u32 },
140 #[error(
141 "Structure member[{index}] at {offset} and size {size} crosses the structure boundary of size {span}"
142 )]
143 MemberOutOfBounds {
144 index: u32,
145 offset: u32,
146 size: u32,
147 span: u32,
148 },
149 #[error("Structure types must have at least one member")]
150 EmptyStruct,
151 #[error(transparent)]
152 WidthError(#[from] WidthError),
153 #[error(
154 "The base handle {0:?} has an override-expression that didn't get resolved to a constant"
155 )]
156 UnresolvedOverride(Handle<crate::Type>),
157}
158
159#[derive(Clone, Debug, thiserror::Error)]
160#[cfg_attr(test, derive(PartialEq))]
161pub enum WidthError {
162 #[error("The {0:?} scalar width {1} is not supported")]
163 Invalid(crate::ScalarKind, crate::Bytes),
164 #[error("Using `{name}` values requires the `naga::valid::Capabilities::{flag}` flag")]
165 MissingCapability {
166 name: &'static str,
167 flag: &'static str,
168 },
169
170 #[error("Abstract types may only appear in constant expressions")]
171 Abstract,
172}
173
174#[derive(Clone, Debug, thiserror::Error)]
175#[cfg_attr(test, derive(PartialEq))]
176pub enum PushConstantError {
177 #[error("The scalar type {0:?} is not supported in push constants")]
178 InvalidScalar(crate::Scalar),
179}
180
181type LayoutCompatibility = Result<Alignment, (Handle<crate::Type>, Disalignment)>;
183type PushConstantCompatibility = Result<(), PushConstantError>;
184
185fn check_member_layout(
186 accum: &mut LayoutCompatibility,
187 member: &crate::StructMember,
188 member_index: u32,
189 member_layout: LayoutCompatibility,
190 parent_handle: Handle<crate::Type>,
191) {
192 *accum = match (*accum, member_layout) {
193 (Ok(cur_alignment), Ok(alignment)) => {
194 if alignment.is_aligned(member.offset) {
195 Ok(cur_alignment.max(alignment))
196 } else {
197 Err((
198 parent_handle,
199 Disalignment::MemberOffset {
200 index: member_index,
201 offset: member.offset,
202 alignment,
203 },
204 ))
205 }
206 }
207 (Err(e), _) | (_, Err(e)) => Err(e),
208 };
209}
210
211const fn ptr_space_argument_flag(space: crate::AddressSpace) -> TypeFlags {
220 use crate::AddressSpace as As;
221 match space {
222 As::Function | As::Private => TypeFlags::ARGUMENT,
223 As::Uniform | As::Storage { .. } | As::Handle | As::PushConstant | As::WorkGroup => {
224 TypeFlags::empty()
225 }
226 }
227}
228
229#[derive(Clone, Debug)]
230pub(super) struct TypeInfo {
231 pub flags: TypeFlags,
232 pub uniform_layout: LayoutCompatibility,
233 pub storage_layout: LayoutCompatibility,
234 pub push_constant_compatibility: PushConstantCompatibility,
235}
236
237impl TypeInfo {
238 const fn dummy() -> Self {
239 TypeInfo {
240 flags: TypeFlags::empty(),
241 uniform_layout: Ok(Alignment::ONE),
242 storage_layout: Ok(Alignment::ONE),
243 push_constant_compatibility: Ok(()),
244 }
245 }
246
247 const fn new(flags: TypeFlags, alignment: Alignment) -> Self {
248 TypeInfo {
249 flags,
250 uniform_layout: Ok(alignment),
251 storage_layout: Ok(alignment),
252 push_constant_compatibility: Ok(()),
253 }
254 }
255}
256
257impl super::Validator {
258 const fn require_type_capability(&self, capability: Capabilities) -> Result<(), TypeError> {
259 if self.capabilities.contains(capability) {
260 Ok(())
261 } else {
262 Err(TypeError::MissingCapability(capability))
263 }
264 }
265
266 pub(super) const fn check_width(
276 &self,
277 scalar: crate::Scalar,
278 ) -> Result<PushConstantCompatibility, WidthError> {
279 let mut push_constant_compatibility = Ok(());
280 let good = match scalar.kind {
281 crate::ScalarKind::Bool => scalar.width == crate::BOOL_WIDTH,
282 crate::ScalarKind::Float => match scalar.width {
283 8 => {
284 if !self.capabilities.contains(Capabilities::FLOAT64) {
285 return Err(WidthError::MissingCapability {
286 name: "f64",
287 flag: "FLOAT64",
288 });
289 }
290 true
291 }
292 2 => {
293 if !self.capabilities.contains(Capabilities::SHADER_FLOAT16) {
294 return Err(WidthError::MissingCapability {
295 name: "f16",
296 flag: "FLOAT16",
297 });
298 }
299
300 push_constant_compatibility = Err(PushConstantError::InvalidScalar(scalar));
301
302 true
303 }
304 _ => scalar.width == 4,
305 },
306 crate::ScalarKind::Sint => {
307 if scalar.width == 8 {
308 if !self.capabilities.contains(Capabilities::SHADER_INT64) {
309 return Err(WidthError::MissingCapability {
310 name: "i64",
311 flag: "SHADER_INT64",
312 });
313 }
314 true
315 } else {
316 scalar.width == 4
317 }
318 }
319 crate::ScalarKind::Uint => {
320 if scalar.width == 8 {
321 if !self.capabilities.contains(Capabilities::SHADER_INT64) {
322 return Err(WidthError::MissingCapability {
323 name: "u64",
324 flag: "SHADER_INT64",
325 });
326 }
327 true
328 } else {
329 scalar.width == 4
330 }
331 }
332 crate::ScalarKind::AbstractInt | crate::ScalarKind::AbstractFloat => {
333 return Err(WidthError::Abstract);
334 }
335 };
336 if good {
337 Ok(push_constant_compatibility)
338 } else {
339 Err(WidthError::Invalid(scalar.kind, scalar.width))
340 }
341 }
342
343 pub(super) fn reset_types(&mut self, size: usize) {
344 self.types.clear();
345 self.types.resize(size, TypeInfo::dummy());
346 self.layouter.clear();
347 }
348
349 pub(super) fn validate_type(
350 &self,
351 handle: Handle<crate::Type>,
352 gctx: crate::proc::GlobalCtx,
353 ) -> Result<TypeInfo, TypeError> {
354 use crate::TypeInner as Ti;
355 Ok(match gctx.types[handle].inner {
356 Ti::Scalar(scalar) => {
357 let push_constant_compatibility = self.check_width(scalar)?;
358 let shareable = if scalar.kind.is_numeric() {
359 TypeFlags::IO_SHAREABLE | TypeFlags::HOST_SHAREABLE
360 } else {
361 TypeFlags::empty()
362 };
363 let mut type_info = TypeInfo::new(
364 TypeFlags::DATA
365 | TypeFlags::SIZED
366 | TypeFlags::COPY
367 | TypeFlags::ARGUMENT
368 | TypeFlags::CONSTRUCTIBLE
369 | TypeFlags::CREATION_RESOLVED
370 | shareable,
371 Alignment::from_width(scalar.width),
372 );
373 type_info.push_constant_compatibility = push_constant_compatibility;
374 type_info
375 }
376 Ti::Vector { size, scalar } => {
377 let push_constant_compatibility = self.check_width(scalar)?;
378 let shareable = if scalar.kind.is_numeric() {
379 TypeFlags::IO_SHAREABLE | TypeFlags::HOST_SHAREABLE
380 } else {
381 TypeFlags::empty()
382 };
383 let mut type_info = TypeInfo::new(
384 TypeFlags::DATA
385 | TypeFlags::SIZED
386 | TypeFlags::COPY
387 | TypeFlags::ARGUMENT
388 | TypeFlags::CONSTRUCTIBLE
389 | TypeFlags::CREATION_RESOLVED
390 | shareable,
391 Alignment::from(size) * Alignment::from_width(scalar.width),
392 );
393 type_info.push_constant_compatibility = push_constant_compatibility;
394 type_info
395 }
396 Ti::Matrix {
397 columns: _,
398 rows,
399 scalar,
400 } => {
401 if scalar.kind != crate::ScalarKind::Float {
402 return Err(TypeError::MatrixElementNotFloat);
403 }
404 let push_constant_compatibility = self.check_width(scalar)?;
405 let mut type_info = TypeInfo::new(
406 TypeFlags::DATA
407 | TypeFlags::SIZED
408 | TypeFlags::COPY
409 | TypeFlags::HOST_SHAREABLE
410 | TypeFlags::ARGUMENT
411 | TypeFlags::CONSTRUCTIBLE
412 | TypeFlags::CREATION_RESOLVED,
413 Alignment::from(rows) * Alignment::from_width(scalar.width),
414 );
415 type_info.push_constant_compatibility = push_constant_compatibility;
416 type_info
417 }
418 Ti::Atomic(scalar) => {
419 match scalar {
420 crate::Scalar {
421 kind: crate::ScalarKind::Sint | crate::ScalarKind::Uint,
422 width: _,
423 } => {
424 if scalar.width == 8
425 && !self.capabilities.intersects(
426 Capabilities::SHADER_INT64_ATOMIC_ALL_OPS
427 | Capabilities::SHADER_INT64_ATOMIC_MIN_MAX,
428 )
429 {
430 return Err(TypeError::MissingCapability(
431 Capabilities::SHADER_INT64_ATOMIC_ALL_OPS,
432 ));
433 }
434 }
435 crate::Scalar::F32 => {
436 if !self
437 .capabilities
438 .contains(Capabilities::SHADER_FLOAT32_ATOMIC)
439 {
440 return Err(TypeError::MissingCapability(
441 Capabilities::SHADER_FLOAT32_ATOMIC,
442 ));
443 }
444 }
445 _ => return Err(TypeError::InvalidAtomicWidth(scalar.kind, scalar.width)),
446 };
447 TypeInfo::new(
448 TypeFlags::DATA
449 | TypeFlags::SIZED
450 | TypeFlags::HOST_SHAREABLE
451 | TypeFlags::CREATION_RESOLVED,
452 Alignment::from_width(scalar.width),
453 )
454 }
455 Ti::Pointer { base, space } => {
456 use crate::AddressSpace as As;
457
458 let base_info = &self.types[base.index()];
459 if !base_info.flags.contains(TypeFlags::DATA) {
460 return Err(TypeError::InvalidPointerBase(base));
461 }
462
463 if !base_info.flags.contains(TypeFlags::SIZED) {
475 match space {
476 As::Storage { .. } => {}
477 _ => {
478 return Err(TypeError::InvalidPointerToUnsized { base, space });
479 }
480 }
481 }
482
483 let argument_flag = ptr_space_argument_flag(space);
488
489 TypeInfo::new(
492 argument_flag
493 | TypeFlags::SIZED
494 | TypeFlags::COPY
495 | TypeFlags::CREATION_RESOLVED,
496 Alignment::ONE,
497 )
498 }
499 Ti::ValuePointer {
500 size: _,
501 scalar,
502 space,
503 } => {
504 let _ = self.check_width(scalar)?;
512
513 let argument_flag = ptr_space_argument_flag(space);
518
519 TypeInfo::new(
522 argument_flag
523 | TypeFlags::SIZED
524 | TypeFlags::COPY
525 | TypeFlags::CREATION_RESOLVED,
526 Alignment::ONE,
527 )
528 }
529 Ti::Array { base, size, stride } => {
530 let base_info = &self.types[base.index()];
531 if !base_info
532 .flags
533 .contains(TypeFlags::DATA | TypeFlags::SIZED | TypeFlags::CREATION_RESOLVED)
534 {
535 return Err(TypeError::InvalidArrayBaseType(base));
536 }
537
538 let base_layout = self.layouter[base];
539 let general_alignment = base_layout.alignment;
540 let uniform_layout = match base_info.uniform_layout {
541 Ok(base_alignment) => {
542 let alignment = base_alignment
543 .max(general_alignment)
544 .max(Alignment::MIN_UNIFORM);
545 if alignment.is_aligned(stride) {
546 Ok(alignment)
547 } else {
548 Err((handle, Disalignment::ArrayStride { stride, alignment }))
549 }
550 }
551 Err(e) => Err(e),
552 };
553 let storage_layout = match base_info.storage_layout {
554 Ok(base_alignment) => {
555 let alignment = base_alignment.max(general_alignment);
556 if alignment.is_aligned(stride) {
557 Ok(alignment)
558 } else {
559 Err((handle, Disalignment::ArrayStride { stride, alignment }))
560 }
561 }
562 Err(e) => Err(e),
563 };
564
565 let type_info_mask = match size {
566 crate::ArraySize::Constant(_) => {
567 TypeFlags::DATA
568 | TypeFlags::SIZED
569 | TypeFlags::COPY
570 | TypeFlags::HOST_SHAREABLE
571 | TypeFlags::ARGUMENT
572 | TypeFlags::CONSTRUCTIBLE
573 | TypeFlags::CREATION_RESOLVED
574 }
575 crate::ArraySize::Pending(_) => {
576 TypeFlags::DATA
577 | TypeFlags::SIZED
578 | TypeFlags::COPY
579 | TypeFlags::HOST_SHAREABLE
580 | TypeFlags::ARGUMENT
581 }
582 crate::ArraySize::Dynamic => {
583 TypeFlags::DATA
587 | TypeFlags::COPY
588 | TypeFlags::HOST_SHAREABLE
589 | TypeFlags::CREATION_RESOLVED
590 }
591 };
592
593 TypeInfo {
594 flags: base_info.flags & type_info_mask,
595 uniform_layout,
596 storage_layout,
597 push_constant_compatibility: base_info.push_constant_compatibility.clone(),
598 }
599 }
600 Ti::Struct { ref members, span } => {
601 if members.is_empty() {
602 return Err(TypeError::EmptyStruct);
603 }
604
605 let mut ti = TypeInfo::new(
606 TypeFlags::DATA
607 | TypeFlags::SIZED
608 | TypeFlags::COPY
609 | TypeFlags::HOST_SHAREABLE
610 | TypeFlags::IO_SHAREABLE
611 | TypeFlags::ARGUMENT
612 | TypeFlags::CONSTRUCTIBLE
613 | TypeFlags::CREATION_RESOLVED,
614 Alignment::ONE,
615 );
616 ti.uniform_layout = Ok(Alignment::MIN_UNIFORM);
617
618 let mut min_offset = 0;
619 let mut prev_struct_data: Option<(u32, u32)> = None;
620
621 for (i, member) in members.iter().enumerate() {
622 let base_info = &self.types[member.ty.index()];
623 if !base_info
624 .flags
625 .contains(TypeFlags::DATA | TypeFlags::CREATION_RESOLVED)
626 {
627 return Err(TypeError::InvalidData(member.ty));
628 }
629 if !base_info.flags.contains(TypeFlags::HOST_SHAREABLE) {
630 if ti.uniform_layout.is_ok() {
631 ti.uniform_layout = Err((member.ty, Disalignment::NonHostShareable));
632 }
633 if ti.storage_layout.is_ok() {
634 ti.storage_layout = Err((member.ty, Disalignment::NonHostShareable));
635 }
636 }
637 ti.flags &= base_info.flags;
638
639 if member.offset < min_offset {
640 if member.offset == 0 {
644 ti.flags.set(TypeFlags::HOST_SHAREABLE, false);
645 } else {
646 return Err(TypeError::MemberOverlap {
647 index: i as u32,
648 offset: member.offset,
649 });
650 }
651 }
652
653 let base_size = gctx.types[member.ty].inner.size(gctx);
654 min_offset = member.offset + base_size;
655 if min_offset > span {
656 return Err(TypeError::MemberOutOfBounds {
657 index: i as u32,
658 offset: member.offset,
659 size: base_size,
660 span,
661 });
662 }
663
664 check_member_layout(
665 &mut ti.uniform_layout,
666 member,
667 i as u32,
668 base_info.uniform_layout,
669 handle,
670 );
671 check_member_layout(
672 &mut ti.storage_layout,
673 member,
674 i as u32,
675 base_info.storage_layout,
676 handle,
677 );
678 if base_info.push_constant_compatibility.is_err() {
679 ti.push_constant_compatibility =
680 base_info.push_constant_compatibility.clone();
681 }
682
683 if let Some((span, offset)) = prev_struct_data {
687 let diff = member.offset - offset;
688 let min = Alignment::MIN_UNIFORM.round_up(span);
689 if diff < min {
690 ti.uniform_layout = Err((
691 handle,
692 Disalignment::MemberOffsetAfterStruct {
693 index: i as u32,
694 offset: member.offset,
695 expected: offset + min,
696 },
697 ));
698 }
699 };
700
701 prev_struct_data = match gctx.types[member.ty].inner {
702 crate::TypeInner::Struct { span, .. } => Some((span, member.offset)),
703 _ => None,
704 };
705
706 if !base_info.flags.contains(TypeFlags::SIZED) {
708 let is_array = match gctx.types[member.ty].inner {
709 crate::TypeInner::Array { .. } => true,
710 _ => false,
711 };
712 if !is_array || i + 1 != members.len() {
713 let name = member.name.clone().unwrap_or_default();
714 return Err(TypeError::InvalidDynamicArray(name, member.ty));
715 }
716 if ti.uniform_layout.is_ok() {
717 ti.uniform_layout =
718 Err((handle, Disalignment::UnsizedMember { index: i as u32 }));
719 }
720 }
721 }
722
723 let alignment = self.layouter[handle].alignment;
724 if !alignment.is_aligned(span) {
725 ti.uniform_layout = Err((handle, Disalignment::StructSpan { span, alignment }));
726 ti.storage_layout = Err((handle, Disalignment::StructSpan { span, alignment }));
727 }
728
729 ti
730 }
731 Ti::Image {
732 dim,
733 arrayed,
734 class,
735 } => {
736 if arrayed && matches!(dim, crate::ImageDimension::D3) {
737 return Err(TypeError::UnsupportedImageType {
738 dim,
739 arrayed,
740 class,
741 });
742 }
743 if arrayed && matches!(dim, crate::ImageDimension::Cube) {
744 self.require_type_capability(Capabilities::CUBE_ARRAY_TEXTURES)?;
745 }
746 if matches!(class, crate::ImageClass::External) {
747 if dim != crate::ImageDimension::D2 || arrayed {
748 return Err(TypeError::UnsupportedImageType {
749 dim,
750 arrayed,
751 class,
752 });
753 }
754 self.require_type_capability(Capabilities::TEXTURE_EXTERNAL)?;
755 }
756 TypeInfo::new(
757 TypeFlags::ARGUMENT | TypeFlags::CREATION_RESOLVED,
758 Alignment::ONE,
759 )
760 }
761 Ti::Sampler { .. } => TypeInfo::new(
762 TypeFlags::ARGUMENT | TypeFlags::CREATION_RESOLVED,
763 Alignment::ONE,
764 ),
765 Ti::AccelerationStructure { vertex_return } => {
766 self.require_type_capability(Capabilities::RAY_QUERY)?;
767 if vertex_return {
768 self.require_type_capability(Capabilities::RAY_HIT_VERTEX_POSITION)?;
769 }
770 TypeInfo::new(
771 TypeFlags::ARGUMENT | TypeFlags::CREATION_RESOLVED,
772 Alignment::ONE,
773 )
774 }
775 Ti::RayQuery { vertex_return } => {
776 self.require_type_capability(Capabilities::RAY_QUERY)?;
777 if vertex_return {
778 self.require_type_capability(Capabilities::RAY_HIT_VERTEX_POSITION)?;
779 }
780 TypeInfo::new(
781 TypeFlags::DATA
782 | TypeFlags::CONSTRUCTIBLE
783 | TypeFlags::SIZED
784 | TypeFlags::CREATION_RESOLVED,
785 Alignment::ONE,
786 )
787 }
788 Ti::BindingArray { base, size } => {
789 let type_info_mask = match size {
790 crate::ArraySize::Constant(_) => {
791 TypeFlags::SIZED | TypeFlags::HOST_SHAREABLE | TypeFlags::CREATION_RESOLVED
792 }
793 crate::ArraySize::Pending(_) => TypeFlags::SIZED | TypeFlags::HOST_SHAREABLE,
794 crate::ArraySize::Dynamic => {
795 TypeFlags::HOST_SHAREABLE | TypeFlags::CREATION_RESOLVED
797 }
798 };
799 let base_info = &self.types[base.index()];
800
801 if base_info.flags.contains(TypeFlags::DATA) {
802 match gctx.types[base].inner {
804 crate::TypeInner::Struct { .. } => {}
805 _ => return Err(TypeError::BindingArrayBaseTypeNotStruct(base)),
806 };
807 }
808 if matches!(
809 gctx.types[base].inner,
810 crate::TypeInner::Image {
811 class: crate::ImageClass::External,
812 ..
813 }
814 ) {
815 return Err(TypeError::BindingArrayBaseExternalTextures);
818 }
819
820 if !base_info.flags.contains(TypeFlags::CREATION_RESOLVED) {
821 return Err(TypeError::InvalidData(base));
822 }
823
824 TypeInfo::new(base_info.flags & type_info_mask, Alignment::ONE)
825 }
826 })
827 }
828}