Skip to content

Commit c5e6c84

Browse files
committed
Support unions in type info reflection
1 parent e7e846e commit c5e6c84

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
@@ -110,12 +110,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
110110
variant
111111
}
112112
ty::Adt(adt_def, generics) => {
113-
// TODO(type_info): Handle union
114-
if !adt_def.is_struct() && !adt_def.is_enum() {
115-
self.downcast(&field_dest, sym::Other)?.0
116-
} else {
117-
self.write_adt_type_info(&field_dest, (ty, *adt_def), generics)?
118-
}
113+
self.write_adt_type_info(&field_dest, (ty, *adt_def), generics)?
119114
}
120115
ty::Bool => {
121116
let (variant, _variant_place) =
@@ -345,13 +340,22 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
345340
)?;
346341
variant
347342
}
343+
AdtKind::Union => {
344+
let (variant, variant_place) = self.downcast(place, sym::Union)?;
345+
let place = self.project_field(&variant_place, FieldIdx::ZERO)?;
346+
self.write_union_type_info(
347+
place,
348+
(adt_ty, adt_def.variant(VariantIdx::ZERO)),
349+
generics,
350+
)?;
351+
variant
352+
}
348353
AdtKind::Enum => {
349354
let (variant, variant_place) = self.downcast(place, sym::Enum)?;
350355
let place = self.project_field(&variant_place, FieldIdx::ZERO)?;
351356
self.write_enum_type_info(place, adt, generics)?;
352357
variant
353358
}
354-
AdtKind::Union => todo!(),
355359
};
356360
interp_ok(variant_idx)
357361
}
@@ -386,6 +390,36 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
386390
interp_ok(())
387391
}
388392

393+
pub(crate) fn write_union_type_info(
394+
&mut self,
395+
place: impl Writeable<'tcx, CtfeProvenance>,
396+
union_: (Ty<'tcx>, &'tcx VariantDef),
397+
generics: &'tcx GenericArgs<'tcx>,
398+
) -> InterpResult<'tcx> {
399+
let (union_ty, union_def) = union_;
400+
let union_layout = self.layout_of(union_ty)?;
401+
402+
for (field_idx, field) in
403+
place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated()
404+
{
405+
let field_place = self.project_field(&place, field_idx)?;
406+
407+
match field.name {
408+
sym::generics => self.write_generics(field_place, generics)?,
409+
sym::fields => {
410+
self.write_variant_fields(field_place, union_def, union_layout, generics)?
411+
}
412+
sym::non_exhaustive => {
413+
let is_non_exhaustive = union_def.is_field_list_non_exhaustive();
414+
self.write_scalar(Scalar::from_bool(is_non_exhaustive), &field_place)?
415+
}
416+
other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"),
417+
}
418+
}
419+
420+
interp_ok(())
421+
}
422+
389423
pub(crate) fn write_enum_type_info(
390424
&mut self,
391425
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
@@ -397,6 +397,7 @@ symbols! {
397397
TyCtxt,
398398
TyKind,
399399
Type,
400+
Union,
400401
Unknown,
401402
Unsize,
402403
UnsizedConstParamTy,

library/core/src/mem/type_info.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ pub enum TypeKind {
4949
Struct(Struct),
5050
/// Enums.
5151
Enum(Enum),
52+
/// Unions.
53+
Union(Union),
5254
/// Primitive boolean type.
5355
Bool(Bool),
5456
/// Primitive character type.
@@ -111,6 +113,17 @@ pub struct Struct {
111113
pub non_exhaustive: bool,
112114
}
113115

116+
/// Compile-time type information about unions.
117+
#[derive(Debug)]
118+
#[non_exhaustive]
119+
#[unstable(feature = "type_info", issue = "146922")]
120+
pub struct Union {
121+
/// Instantiated generics of the union.
122+
pub generics: &'static [Generic],
123+
/// All fields of the union.
124+
pub fields: &'static [Field],
125+
}
126+
114127
/// Compile-time type information about enums.
115128
#[derive(Debug)]
116129
#[non_exhaustive]

library/coretests/tests/mem/type_info.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,47 @@ fn test_structs() {
119119
}
120120
}
121121

122+
#[test]
123+
fn test_unions() {
124+
use TypeKind::*;
125+
126+
const {
127+
union TestUnion {
128+
first: i16,
129+
second: u16,
130+
}
131+
132+
let Type { kind: Union(ty), size, .. } = Type::of::<TestUnion>() else { panic!() };
133+
assert!(size == Some(size_of::<TestUnion>()));
134+
assert!(ty.fields.len() == 2);
135+
assert!(ty.fields[0].name == "first");
136+
assert!(ty.fields[0].offset == 0);
137+
assert!(ty.fields[1].name == "second");
138+
assert!(ty.fields[1].offset == 0);
139+
}
140+
141+
const {
142+
union Generics<'a, T: Copy, const C: u64> {
143+
a: T,
144+
z: &'a (),
145+
}
146+
147+
let Type { kind: Union(ty), .. } = Type::of::<Generics<'static, i32, 1_u64>>() else {
148+
panic!()
149+
};
150+
assert!(ty.fields.len() == 2);
151+
assert!(ty.fields[0].offset == 0);
152+
assert!(ty.fields[1].offset == 0);
153+
154+
assert!(ty.generics.len() == 3);
155+
let Generic::Lifetime(_) = ty.generics[0] else { panic!() };
156+
let Generic::Type(GenericType { ty: generic_ty, .. }) = ty.generics[1] else { panic!() };
157+
assert!(generic_ty == TypeId::of::<i32>());
158+
let Generic::Const(Const { ty: const_ty, .. }) = ty.generics[2] else { panic!() };
159+
assert!(const_ty == TypeId::of::<u64>());
160+
}
161+
}
162+
122163
#[test]
123164
fn test_enums() {
124165
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)