Skip to content

Commit f0ae098

Browse files
committed
Support unions in type info reflection
1 parent bca10e1 commit f0ae098

7 files changed

Lines changed: 146 additions & 8 deletions

File tree

compiler/rustc_const_eval/src/const_eval/type_info.rs

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -119,12 +119,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
119119
variant
120120
}
121121
ty::Adt(adt_def, generics) => {
122-
// TODO(type_info): Handle union
123-
if !adt_def.is_struct() && !adt_def.is_enum() {
124-
self.downcast(&field_dest, sym::Other)?.0
125-
} else {
126-
self.write_adt_type_info(&field_dest, (ty, *adt_def), generics)?
127-
}
122+
self.write_adt_type_info(&field_dest, (ty, *adt_def), generics)?
128123
}
129124
ty::Bool => {
130125
let (variant, _variant_place) =
@@ -389,13 +384,22 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
389384
)?;
390385
variant
391386
}
387+
AdtKind::Union => {
388+
let (variant, variant_place) = self.downcast(place, sym::Union)?;
389+
let place = self.project_field(&variant_place, FieldIdx::ZERO)?;
390+
self.write_union_type_info(
391+
place,
392+
(adt_ty, adt_def.variant(VariantIdx::ZERO)),
393+
generics,
394+
)?;
395+
variant
396+
}
392397
AdtKind::Enum => {
393398
let (variant, variant_place) = self.downcast(place, sym::Enum)?;
394399
let place = self.project_field(&variant_place, FieldIdx::ZERO)?;
395400
self.write_enum_type_info(place, adt, generics)?;
396401
variant
397402
}
398-
AdtKind::Union => todo!(),
399403
};
400404
interp_ok(variant_idx)
401405
}
@@ -430,6 +434,36 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
430434
interp_ok(())
431435
}
432436

437+
pub(crate) fn write_union_type_info(
438+
&mut self,
439+
place: impl Writeable<'tcx, CtfeProvenance>,
440+
union_: (Ty<'tcx>, &'tcx VariantDef),
441+
generics: &'tcx GenericArgs<'tcx>,
442+
) -> InterpResult<'tcx> {
443+
let (union_ty, union_def) = union_;
444+
let union_layout = self.layout_of(union_ty)?;
445+
446+
for (field_idx, field) in
447+
place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated()
448+
{
449+
let field_place = self.project_field(&place, field_idx)?;
450+
451+
match field.name {
452+
sym::generics => self.write_generics(field_place, generics)?,
453+
sym::fields => {
454+
self.write_variant_fields(field_place, union_def, union_layout, generics)?
455+
}
456+
sym::non_exhaustive => {
457+
let is_non_exhaustive = union_def.is_field_list_non_exhaustive();
458+
self.write_scalar(Scalar::from_bool(is_non_exhaustive), &field_place)?
459+
}
460+
other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"),
461+
}
462+
}
463+
464+
interp_ok(())
465+
}
466+
433467
pub(crate) fn write_enum_type_info(
434468
&mut self,
435469
place: impl Writeable<'tcx, CtfeProvenance>,

compiler/rustc_span/src/symbol.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,7 @@ symbols! {
400400
TyCtxt,
401401
TyKind,
402402
Type,
403+
Union,
403404
Unknown,
404405
Unsize,
405406
UnsizedConstParamTy,

library/core/src/mem/type_info.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ pub enum TypeKind {
5353
Struct(Struct),
5454
/// Enums.
5555
Enum(Enum),
56+
/// Unions.
57+
Union(Union),
5658
/// Primitive boolean type.
5759
Bool(Bool),
5860
/// Primitive character type.
@@ -156,6 +158,17 @@ pub struct Struct {
156158
pub non_exhaustive: bool,
157159
}
158160

161+
/// Compile-time type information about unions.
162+
#[derive(Debug)]
163+
#[non_exhaustive]
164+
#[unstable(feature = "type_info", issue = "146922")]
165+
pub struct Union {
166+
/// Instantiated generics of the union.
167+
pub generics: &'static [Generic],
168+
/// All fields of the union.
169+
pub fields: &'static [Field],
170+
}
171+
159172
/// Compile-time type information about enums.
160173
#[derive(Debug)]
161174
#[non_exhaustive]

library/coretests/tests/mem/type_info.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,47 @@ fn test_structs() {
127127
}
128128
}
129129

130+
#[test]
131+
fn test_unions() {
132+
use TypeKind::*;
133+
134+
const {
135+
union TestUnion {
136+
first: i16,
137+
second: u16,
138+
}
139+
140+
let Type { kind: Union(ty), size, .. } = Type::of::<TestUnion>() else { panic!() };
141+
assert!(size == Some(size_of::<TestUnion>()));
142+
assert!(ty.fields.len() == 2);
143+
assert!(ty.fields[0].name == "first");
144+
assert!(ty.fields[0].offset == 0);
145+
assert!(ty.fields[1].name == "second");
146+
assert!(ty.fields[1].offset == 0);
147+
}
148+
149+
const {
150+
union Generics<'a, T: Copy, const C: u64> {
151+
a: T,
152+
z: &'a (),
153+
}
154+
155+
let Type { kind: Union(ty), .. } = Type::of::<Generics<'static, i32, 1_u64>>() else {
156+
panic!()
157+
};
158+
assert!(ty.fields.len() == 2);
159+
assert!(ty.fields[0].offset == 0);
160+
assert!(ty.fields[1].offset == 0);
161+
162+
assert!(ty.generics.len() == 3);
163+
let Generic::Lifetime(_) = ty.generics[0] else { panic!() };
164+
let Generic::Type(GenericType { ty: generic_ty, .. }) = ty.generics[1] else { panic!() };
165+
assert!(generic_ty == TypeId::of::<i32>());
166+
let Generic::Const(Const { ty: const_ty, .. }) = ty.generics[2] else { panic!() };
167+
assert!(const_ty == TypeId::of::<u64>());
168+
}
169+
}
170+
130171
#[test]
131172
fn test_enums() {
132173
use TypeKind::*;

tests/ui/reflection/dump.bit32.run.stdout

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,28 @@ Type {
296296
12,
297297
),
298298
}
299+
Type {
300+
kind: Union(
301+
Union {
302+
generics: [],
303+
fields: [
304+
Field {
305+
name: "first",
306+
ty: TypeId(0xdeb66dd04fa9db03298cc77926096aae),
307+
offset: 0,
308+
},
309+
Field {
310+
name: "second",
311+
ty: TypeId(0xc50c4a8d8e150aa67101203f1fab1cd7),
312+
offset: 0,
313+
},
314+
],
315+
},
316+
),
317+
size: Some(
318+
2,
319+
),
320+
}
299321
Type {
300322
kind: Reference(
301323
Reference {

tests/ui/reflection/dump.bit64.run.stdout

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,28 @@ Type {
296296
16,
297297
),
298298
}
299+
Type {
300+
kind: Union(
301+
Union {
302+
generics: [],
303+
fields: [
304+
Field {
305+
name: "first",
306+
ty: TypeId(0xdeb66dd04fa9db03298cc77926096aae),
307+
offset: 0,
308+
},
309+
Field {
310+
name: "second",
311+
ty: TypeId(0xc50c4a8d8e150aa67101203f1fab1cd7),
312+
offset: 0,
313+
},
314+
],
315+
},
316+
),
317+
size: Some(
318+
2,
319+
),
320+
}
299321
Type {
300322
kind: Reference(
301323
Reference {

tests/ui/reflection/dump.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ struct Unsized {
4242
s: str,
4343
}
4444

45+
union Union {
46+
first: i16,
47+
second: u16,
48+
}
49+
4550
macro_rules! dump_types {
4651
($($ty:ty),+ $(,)?) => {
4752
$(println!("{:#?}", const { Type::of::<$ty>() });)+
@@ -54,7 +59,7 @@ fn main() {
5459
[u8; 2],
5560
i8, i32, i64, i128, isize,
5661
u8, u32, u64, u128, usize,
57-
Foo, Bar, NonExhaustiveStruct, TupleStruct, Generics<i32, u32, 1>,
62+
Foo, Bar, NonExhaustiveStruct, TupleStruct, Generics<i32, u32, 1>, Union,
5863
&Unsized, &str, &[u8],
5964
str, [u8],
6065
&u8, &mut u8,

0 commit comments

Comments
 (0)