Browse Source

Merge `raw_union` into `struct` as a memory layout tag `#raw_union`

Ginger Bill 8 years ago
parent
commit
59fb7b020a
11 changed files with 237 additions and 289 deletions
  1. 29 30
      code/demo.odin
  2. 1 1
      core/_preload.odin
  3. 5 5
      core/_soft_numbers.odin
  4. 62 53
      src/check_expr.cpp
  5. 0 1
      src/checker.cpp
  6. 28 36
      src/ir.cpp
  7. 8 9
      src/ir_print.cpp
  8. 21 39
      src/parser.cpp
  9. 1 1
      src/ssa.cpp
  10. 1 1
      src/tokenizer.cpp
  11. 81 113
      src/types.cpp

+ 29 - 30
code/demo.odin

@@ -130,18 +130,16 @@ get_hash :: proc(s: string) -> u32 {
 
 
 
-Vector :: struct(N: int, T: type) {
-	using _: raw_union {
-		using e: [N]T;
-		when 0 < N && N <= 4 {
-			using v: struct {
-				when N >= 1 do x: T;
-				when N >= 2 do y: T;
-				when N >= 3 do z: T;
-				when N >= 4 do w: T;
-			};
-
-}	};
+Vector :: struct(N: int, T: type) #raw_union {
+	using e: [N]T;
+	when 0 < N && N <= 4 {
+		using v: struct {
+			when N >= 1 do x: T;
+			when N >= 2 do y: T;
+			when N >= 3 do z: T;
+			when N >= 4 do w: T;
+		};
+	}
 }
 
 Vector3 :: Vector(3, f32);
@@ -161,17 +159,17 @@ foo3 :: proc(a: type/Vector(3, $T))  { fmt.println("foo3", a{}); }
 
 
 main :: proc() {
-	Foo :: struct {
-		a := 123;
-		b := true;
-	}
-	v1 := Foo{};
-	fmt.println(v1);
+	// Foo :: struct {
+	// 	a := 123;
+	// 	b := true;
+	// }
+	// v1 := Foo{};
+	// fmt.println(v1);
 
-	foo1(Vector(3, f32));
-	foo1(Vector3);
-	foo3(Vector(3, f32));
-	foo3(Vector3);
+	// foo1(Vector(3, f32));
+	// foo1(Vector3);
+	// foo3(Vector(3, f32));
+	// foo3(Vector3);
 
 
 	a, b: Vector3;
@@ -184,17 +182,18 @@ main :: proc() {
 	b.z = 5;
 
 	v := add(a, b);
-	fmt.println(v.v);
+	fmt.println(size_of(Vector3));
+	fmt.println(v.e, v.v);
 
-	table: Table(string, int);
+	// table: Table(string, int);
 
-	for i in 0..36 do put(&table, "Hellope", i);
-	for i in 0..42 do put(&table, "World!",  i);
+	// for i in 0..36 do put(&table, "Hellope", i);
+	// for i in 0..42 do put(&table, "World!",  i);
 
 
-	found, _ := find(&table, "Hellope");
-	fmt.printf("found is %v\n", found);
+	// found, _ := find(&table, "Hellope");
+	// fmt.printf("found is %v\n", found);
 
-	found, _ = find(&table, "World!");
-	fmt.printf("found is %v\n", found);
+	// found, _ = find(&table, "World!");
+	// fmt.printf("found is %v\n", found);
 }

+ 1 - 1
core/_preload.odin

@@ -38,7 +38,7 @@ CallingConvention :: enum {
 // The compiler relies upon this _exact_ order
 TypeInfo :: struct #ordered {
 // Core Types
-	EnumValue :: raw_union {
+	EnumValue :: struct #raw_union {
 		f: f64;
 		i: i128;
 	}

+ 5 - 5
core/_soft_numbers.odin

@@ -6,12 +6,12 @@ __multi3 :: proc(a, b: u128) -> u128 #cc_c #link_name "__multi3" {
 
 
 	when ODIN_ENDIAN == "bit" {
-		TWords :: raw_union {
+		TWords :: struct #raw_union {
 			all: u128;
 			using _: struct {lo, hi: u64;};
 		};
 	} else {
-		TWords :: raw_union {
+		TWords :: struct #raw_union {
 			all: u128;
 			using _: struct {hi, lo: u64;};
 		};
@@ -106,7 +106,7 @@ __u128_quo_mod :: proc(a, b: u128, rem: ^u128) -> (quo: u128) #cc_c #link_name "
 __f16_to_f32 :: proc(f: f16) -> f32 #cc_c #no_inline #link_name "__gnu_h2f_ieee" {
 	when true {
 		// Source: https://fgiesen.wordpress.com/2012/03/28/half-to-float-done-quic/
-		FP32 :: raw_union {u: u32, f: f32};
+		FP32 :: struct #raw_union {u: u32, f: f32};
 
 		magic, was_infnan: FP32;
 		magic.u = (254-15) << 23;
@@ -130,8 +130,8 @@ __f16_to_f32 :: proc(f: f16) -> f32 #cc_c #no_inline #link_name "__gnu_h2f_ieee"
 __f32_to_f16 :: proc(f_: f32) -> f16 #cc_c #no_inline #link_name "__gnu_f2h_ieee" {
 	when false {
 		// Source: https://gist.github.com/rygorous/2156668
-		FP16 :: raw_union {u: u16, f: f16};
-		FP32 :: raw_union {u: u32, f: f32};
+		FP16 :: struct #raw_union {u: u16, f: f16};
+		FP32 :: struct #raw_union {u: u32, f: f32};
 
 		f32infty, f16infty, magic: FP32;
 		f32infty.u = 255<<23;

+ 62 - 53
src/check_expr.cpp

@@ -1055,6 +1055,8 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node, Array<Opera
 	GB_ASSERT(is_type_struct(struct_type));
 	ast_node(st, StructType, node);
 
+	String context = str_lit("struct");
+
 	isize min_field_count = 0;
 	for_array(field_index, st->fields) {
 	AstNode *field = st->fields[field_index];
@@ -1066,6 +1068,11 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node, Array<Opera
 	}
 	struct_type->Record.names = make_names_field_for_record(c, c->context.scope);
 
+	if (st->is_raw_union) {
+		struct_type->Record.is_raw_union = true;
+		context = str_lit("struct #raw_union");
+	}
+
 	Type *polymorphic_params = nullptr;
 	bool is_polymorphic = false;
 	bool can_check_fields = true;
@@ -1218,7 +1225,7 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node, Array<Opera
 	Array<Entity *> fields = {};
 
 	if (!is_polymorphic) {
-		fields = check_fields(c, node, st->fields, min_field_count, str_lit("struct"));
+		fields = check_fields(c, node, st->fields, min_field_count, context);
 	}
 
 	struct_type->Record.scope               = c->context.scope;
@@ -1232,35 +1239,36 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node, Array<Opera
 	struct_type->Record.is_poly_specialized = is_poly_specialized;
 
 
-	type_set_offsets(c->allocator, struct_type);
+	if (!struct_type->Record.is_raw_union) {
+		type_set_offsets(c->allocator, struct_type);
 
+		if (!struct_type->failure && !st->is_packed && !st->is_ordered) {
+			struct_type->failure = false;
+			struct_type->Record.are_offsets_set = false;
+			struct_type->Record.offsets = nullptr;
+			// NOTE(bill): Reorder fields for reduced size/performance
 
-	if (!struct_type->failure && !st->is_packed && !st->is_ordered) {
-		struct_type->failure = false;
-		struct_type->Record.are_offsets_set = false;
-		struct_type->Record.offsets = nullptr;
-		// NOTE(bill): Reorder fields for reduced size/performance
+			Entity **reordered_fields = gb_alloc_array(c->allocator, Entity *, fields.count);
+			for (isize i = 0; i < fields.count; i++) {
+				reordered_fields[i] = struct_type->Record.fields_in_src_order[i];
+			}
 
-		Entity **reordered_fields = gb_alloc_array(c->allocator, Entity *, fields.count);
-		for (isize i = 0; i < fields.count; i++) {
-			reordered_fields[i] = struct_type->Record.fields_in_src_order[i];
-		}
+			// NOTE(bill): Hacky thing
+			// TODO(bill): Probably make an inline sorting procedure rather than use global variables
+			__checker_allocator = c->allocator;
+			// NOTE(bill): compound literal order must match source not layout
+			gb_sort_array(reordered_fields, fields.count, cmp_reorder_struct_fields);
 
-		// NOTE(bill): Hacky thing
-		// TODO(bill): Probably make an inline sorting procedure rather than use global variables
-		__checker_allocator = c->allocator;
-		// NOTE(bill): compound literal order must match source not layout
-		gb_sort_array(reordered_fields, fields.count, cmp_reorder_struct_fields);
+			for (isize i = 0; i < fields.count; i++) {
+				reordered_fields[i]->Variable.field_index = i;
+			}
 
-		for (isize i = 0; i < fields.count; i++) {
-			reordered_fields[i]->Variable.field_index = i;
+			struct_type->Record.fields = reordered_fields;
 		}
 
-		struct_type->Record.fields = reordered_fields;
+		type_set_offsets(c->allocator, struct_type);
 	}
 
-	type_set_offsets(c->allocator, struct_type);
-
 
 	if (st->align != nullptr) {
 		if (st->is_packed) {
@@ -1353,29 +1361,29 @@ void check_union_type(Checker *c, Type *named_type, Type *union_type, AstNode *n
 	union_type->Union.variant_count = variants.count;
 }
 
-void check_raw_union_type(Checker *c, Type *union_type, AstNode *node) {
-	GB_ASSERT(node->kind == AstNode_RawUnionType);
-	GB_ASSERT(is_type_raw_union(union_type));
-	ast_node(ut, RawUnionType, node);
+// void check_raw_union_type(Checker *c, Type *union_type, AstNode *node) {
+// 	GB_ASSERT(node->kind == AstNode_RawUnionType);
+// 	GB_ASSERT(is_type_raw_union(union_type));
+// 	ast_node(ut, RawUnionType, node);
 
-	isize min_field_count = 0;
-	for_array(i, ut->fields) {
-		AstNode *field = ut->fields[i];
-		switch (field->kind) {
-		case_ast_node(f, ValueDecl, field);
-			min_field_count += f->names.count;
-		case_end;
-		}
-	}
+// 	isize min_field_count = 0;
+// 	for_array(i, ut->fields) {
+// 		AstNode *field = ut->fields[i];
+// 		switch (field->kind) {
+// 		case_ast_node(f, ValueDecl, field);
+// 			min_field_count += f->names.count;
+// 		case_end;
+// 		}
+// 	}
 
-	union_type->Record.names = make_names_field_for_record(c, c->context.scope);
+// 	union_type->Record.names = make_names_field_for_record(c, c->context.scope);
 
-	auto fields = check_fields(c, node, ut->fields, min_field_count, str_lit("raw_union"));
+// 	auto fields = check_fields(c, node, ut->fields, min_field_count, str_lit("raw_union"));
 
-	union_type->Record.scope       = c->context.scope;
-	union_type->Record.fields      = fields.data;
-	union_type->Record.field_count = fields.count;
-}
+// 	union_type->Record.scope       = c->context.scope;
+// 	union_type->Record.fields      = fields.data;
+// 	union_type->Record.field_count = fields.count;
+// }
 
 
 void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *node) {
@@ -3018,7 +3026,7 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
 		return true;
 	case_end;
 
-	case_ast_node(rut, RawUnionType, e);
+/* 	case_ast_node(rut, RawUnionType, e);
 		*type = make_type_raw_union(c->allocator);
 		set_base_type(named_type, *type);
 		check_open_scope(c, e);
@@ -3027,7 +3035,7 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
 		(*type)->Record.node = e;
 		return true;
 	case_end;
-
+ */
 	case_ast_node(et, EnumType, e);
 		*type = make_type_enum(c->allocator);
 		set_base_type(named_type, *type);
@@ -6482,7 +6490,7 @@ CallArgumentError check_polymorphic_struct_type(Checker *c, Operand *operand, As
 
 	Type *original_type = operand->type;
 	Type *struct_type = base_type(operand->type);
-	GB_ASSERT(is_type_struct(struct_type));
+	GB_ASSERT(struct_type->kind == Type_Record);
 	TypeRecord *st = &struct_type->Record;
 	GB_ASSERT(st->is_polymorphic);
 
@@ -7738,7 +7746,7 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
 			valid = false;
 		}
 
-		if (!valid && (is_type_struct(t) || is_type_raw_union(t))) {
+		if (!valid && t->kind == Type_Record) {
 			Entity *found = find_using_index_expr(t);
 			if (found != nullptr) {
 				valid = check_set_index_data(o, found->type, is_type_pointer(found->type), &max_count);
@@ -7937,7 +7945,7 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
 	case AstNode_VectorType:
 	case AstNode_StructType:
 	case AstNode_UnionType:
-	case AstNode_RawUnionType:
+	// case AstNode_RawUnionType:
 	case AstNode_EnumType:
 	case AstNode_MapType:
 		o->mode = Addressing_Type;
@@ -8351,19 +8359,20 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
 
 	case_ast_node(st, StructType, node);
 		str = gb_string_appendc(str, "struct ");
-		if (st->is_packed)  str = gb_string_appendc(str, "#packed ");
-		if (st->is_ordered) str = gb_string_appendc(str, "#ordered ");
+		if (st->is_packed)    str = gb_string_appendc(str, "#packed ");
+		if (st->is_ordered)   str = gb_string_appendc(str, "#ordered ");
+		if (st->is_raw_union) str = gb_string_appendc(str, "#raw_union ");
 		str = gb_string_appendc(str, "{");
 		str = write_record_fields_to_string(str, st->fields);
 		str = gb_string_appendc(str, "}");
 	case_end;
 
-	case_ast_node(st, RawUnionType, node);
-		str = gb_string_appendc(str, "raw_union ");
-		str = gb_string_appendc(str, "{");
-		str = write_record_fields_to_string(str, st->fields);
-		str = gb_string_appendc(str, "}");
-	case_end;
+	// case_ast_node(st, RawUnionType, node);
+	// 	str = gb_string_appendc(str, "raw_union ");
+	// 	str = gb_string_appendc(str, "{");
+	// 	str = write_record_fields_to_string(str, st->fields);
+	// 	str = gb_string_appendc(str, "}");
+	// case_end;
 
 	case_ast_node(st, UnionType, node);
 		str = gb_string_appendc(str, "union ");

+ 0 - 1
src/checker.cpp

@@ -472,7 +472,6 @@ void check_open_scope(Checker *c, AstNode *node) {
 	case AstNode_StructType:
 	case AstNode_EnumType:
 	case AstNode_UnionType:
-	case AstNode_RawUnionType:
 		scope->is_record = true;
 		break;
 	}

+ 28 - 36
src/ir.cpp

@@ -662,7 +662,7 @@ bool ir_type_has_default_values(Type *t) {
 		return ir_type_has_default_values(t->Array.elem);
 
 	case Type_Record:
-		if (t->Record.kind == TypeRecord_Struct) {
+		if (!t->Record.is_raw_union) {
 			for (isize i = 0; i < t->Record.field_count; i++) {
 				Entity *f = t->Record.fields_in_src_order[i];
 				if (f->kind != Entity_Variable) continue;
@@ -7355,12 +7355,7 @@ void ir_init_module(irModule *m, Checker *c) {
 					count += t->Union.variant_count;
 					break;
 				case Type_Record:
-					switch (t->Record.kind) {
-					case TypeRecord_Struct:
-					case TypeRecord_RawUnion:
-						count += t->Record.field_count;
-						break;
-					}
+					count += t->Record.field_count;
 					break;
 				case Type_Tuple:
 					count += t->Tuple.variable_count;
@@ -8193,8 +8188,32 @@ void ir_gen_tree(irGen *s) {
 				} break;
 
 				case Type_Record: {
-					switch (t->Record.kind) {
-					case TypeRecord_Struct: {
+					if (t->Record.is_raw_union) {
+						ir_emit_comment(proc, str_lit("TypeInfoRawUnion"));
+						tag = ir_emit_conv(proc, variant_ptr, t_type_info_raw_union_ptr);
+
+						irValue *memory_types   = ir_type_info_member_types_offset(proc, t->Record.field_count);
+						irValue *memory_names   = ir_type_info_member_names_offset(proc, t->Record.field_count);
+						irValue *memory_offsets = ir_type_info_member_offsets_offset(proc, t->Record.field_count);
+
+						for (isize i = 0; i < t->Record.field_count; i++) {
+							Entity *f = t->Record.fields[i];
+							irValue *index     = ir_const_int(a, i);
+							irValue *type_info = ir_emit_ptr_offset(proc, memory_types, index);
+							// NOTE(bill): Offsets are always 0
+
+							ir_emit_store(proc, type_info, ir_type_info(proc, f->type));
+							if (f->token.string.len > 0) {
+								irValue *name = ir_emit_ptr_offset(proc, memory_names, index);
+								ir_emit_store(proc, name, ir_const_string(a, f->token.string));
+							}
+						}
+
+						irValue *count = ir_const_int(a, t->Record.field_count);
+						ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 0), memory_types,   count, count);
+						ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 1), memory_names,   count, count);
+						ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 2), memory_offsets, count, count);
+					} else {
 						ir_emit_comment(proc, str_lit("TypeInfoStruct"));
 						tag = ir_emit_conv(proc, variant_ptr, t_type_info_struct_ptr);
 
@@ -8239,33 +8258,6 @@ void ir_gen_tree(irGen *s) {
 						ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 1), memory_names,   count, count);
 						ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 2), memory_offsets, count, count);
 						ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 3), memory_usings,  count, count);
-					} break;
-					case TypeRecord_RawUnion: {
-						ir_emit_comment(proc, str_lit("TypeInfoRawUnion"));
-						tag = ir_emit_conv(proc, variant_ptr, t_type_info_raw_union_ptr);
-
-						irValue *memory_types   = ir_type_info_member_types_offset(proc, t->Record.field_count);
-						irValue *memory_names   = ir_type_info_member_names_offset(proc, t->Record.field_count);
-						irValue *memory_offsets = ir_type_info_member_offsets_offset(proc, t->Record.field_count);
-
-						for (isize i = 0; i < t->Record.field_count; i++) {
-							Entity *f = t->Record.fields[i];
-							irValue *index     = ir_const_int(a, i);
-							irValue *type_info = ir_emit_ptr_offset(proc, memory_types, index);
-							// NOTE(bill): Offsets are always 0
-
-							ir_emit_store(proc, type_info, ir_type_info(proc, f->type));
-							if (f->token.string.len > 0) {
-								irValue *name = ir_emit_ptr_offset(proc, memory_names, index);
-								ir_emit_store(proc, name, ir_const_string(a, f->token.string));
-							}
-						}
-
-						irValue *count = ir_const_int(a, t->Record.field_count);
-						ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 0), memory_types,   count, count);
-						ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 1), memory_names,   count, count);
-						ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 2), memory_offsets, count, count);
-					} break;
 					}
 				} break;
 				case Type_Map: {

+ 8 - 9
src/ir_print.cpp

@@ -300,8 +300,14 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
 	} return;
 
 	case Type_Record: {
-		switch (t->Record.kind) {
-		case TypeRecord_Struct:
+		if (t->Record.is_raw_union) {
+			// NOTE(bill): The zero size array is used to fix the alignment used in a structure as
+			// LLVM takes the first element's alignment as the entire alignment (like C)
+			i64 size_of_union  = type_size_of(heap_allocator(), t);
+			i64 align_of_union = type_align_of(heap_allocator(), t);
+			ir_fprintf(f, "{[0 x <%lld x i8>], [%lld x i8]}", align_of_union, size_of_union);
+			return;
+		} else {
 			if (t->Record.is_packed) {
 				ir_fprintf(f, "<");
 			}
@@ -323,13 +329,6 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
 				ir_fprintf(f, ">");
 			}
 			return;
-		case TypeRecord_RawUnion: {
-			// NOTE(bill): The zero size array is used to fix the alignment used in a structure as
-			// LLVM takes the first element's alignment as the entire alignment (like C)
-			i64 size_of_union  = type_size_of(heap_allocator(), t);
-			i64 align_of_union = type_align_of(heap_allocator(), t);
-			ir_fprintf(f, "{[0 x <%lld x i8>], [%lld x i8]}", align_of_union, size_of_union);
-		} return;
 		}
 	} break;
 

+ 21 - 39
src/parser.cpp

@@ -423,17 +423,13 @@ AST_NODE_KIND(_TypeBegin, "", i32) \
 		AstNode *        polymorphic_params;  \
 		bool             is_packed;           \
 		bool             is_ordered;          \
+		bool             is_raw_union;        \
 		AstNode *        align;               \
 	}) \
 	AST_NODE_KIND(UnionType, "union type", struct { \
 		Token            token;       \
 		Array<AstNode *> variants;    \
 	}) \
-	AST_NODE_KIND(RawUnionType, "raw union type", struct { \
-		Token            token; \
-		Array<AstNode *> fields; \
-		isize            field_count; \
-	}) \
 	AST_NODE_KIND(EnumType, "enum type", struct { \
 		Token            token; \
 		AstNode *        base_type; \
@@ -599,7 +595,6 @@ Token ast_node_token(AstNode *node) {
 	case AstNode_VectorType:       return node->VectorType.token;
 	case AstNode_StructType:       return node->StructType.token;
 	case AstNode_UnionType:        return node->UnionType.token;
-	case AstNode_RawUnionType:     return node->RawUnionType.token;
 	case AstNode_EnumType:         return node->EnumType.token;
 	case AstNode_BitFieldType:     return node->BitFieldType.token;
 	case AstNode_MapType:          return node->MapType.token;
@@ -868,9 +863,6 @@ AstNode *clone_ast_node(gbAllocator a, AstNode *node) {
 	case AstNode_UnionType:
 		n->UnionType.variants = clone_ast_node_array(a, n->UnionType.variants);
 		break;
-	case AstNode_RawUnionType:
-		n->RawUnionType.fields = clone_ast_node_array(a, n->RawUnionType.fields);
-		break;
 	case AstNode_EnumType:
 		n->EnumType.base_type = clone_ast_node(a, n->EnumType.base_type);
 		n->EnumType.fields    = clone_ast_node_array(a, n->EnumType.fields);
@@ -1451,7 +1443,8 @@ AstNode *ast_vector_type(AstFile *f, Token token, AstNode *count, AstNode *elem)
 }
 
 AstNode *ast_struct_type(AstFile *f, Token token, Array<AstNode *> fields, isize field_count,
-                         AstNode *polymorphic_params, bool is_packed, bool is_ordered, AstNode *align) {
+                         AstNode *polymorphic_params, bool is_packed, bool is_ordered, bool is_raw_union,
+                         AstNode *align) {
 	AstNode *result = make_ast_node(f, AstNode_StructType);
 	result->StructType.token              = token;
 	result->StructType.fields             = fields;
@@ -1459,6 +1452,7 @@ AstNode *ast_struct_type(AstFile *f, Token token, Array<AstNode *> fields, isize
 	result->StructType.polymorphic_params = polymorphic_params;
 	result->StructType.is_packed          = is_packed;
 	result->StructType.is_ordered         = is_ordered;
+	result->StructType.is_raw_union       = is_raw_union;
 	result->StructType.align              = align;
 	return result;
 }
@@ -1471,14 +1465,6 @@ AstNode *ast_union_type(AstFile *f, Token token, Array<AstNode *> variants) {
 	return result;
 }
 
-AstNode *ast_raw_union_type(AstFile *f, Token token, Array<AstNode *> fields, isize field_count) {
-	AstNode *result = make_ast_node(f, AstNode_RawUnionType);
-	result->RawUnionType.token = token;
-	result->RawUnionType.fields = fields;
-	result->RawUnionType.field_count = field_count;
-	return result;
-}
-
 
 AstNode *ast_enum_type(AstFile *f, Token token, AstNode *base_type, Array<AstNode *> fields) {
 	AstNode *result = make_ast_node(f, AstNode_EnumType);
@@ -1837,7 +1823,6 @@ bool is_semicolon_optional_for_node(AstFile *f, AstNode *s) {
 
 	case AstNode_StructType:
 	case AstNode_UnionType:
-	case AstNode_RawUnionType:
 	case AstNode_EnumType:
 	case AstNode_BitFieldType:
 		return true;
@@ -2424,8 +2409,9 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
 	case Token_struct: {
 		Token token = expect_token(f, Token_struct);
 		AstNode *polymorphic_params = nullptr;
-		bool is_packed = false;
-		bool is_ordered = false;
+		bool is_packed    = false;
+		bool is_ordered   = false;
+		bool is_raw_union = false;
 		AstNode *align = nullptr;
 
 		if (allow_token(f, Token_OpenParen)) {
@@ -2458,6 +2444,11 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
 					syntax_error(tag, "Duplicate struct tag `#%.*s`", LIT(tag.string));
 				}
 				align = parse_expr(f, true);
+			} else if (tag.string == "raw_union") {
+				if (is_raw_union) {
+					syntax_error(tag, "Duplicate struct tag `#%.*s`", LIT(tag.string));
+				}
+				is_raw_union = true;
 			} else {
 				syntax_error(tag, "Invalid struct tag `#%.*s`", LIT(tag.string));
 			}
@@ -2468,6 +2459,14 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
 		if (is_packed && is_ordered) {
 			syntax_error(token, "`#ordered` is not needed with `#packed` which implies ordering");
 		}
+		if (is_raw_union && is_packed) {
+			is_packed = false;
+			syntax_error(token, "`#raw_union` cannot also be `#packed`");
+		}
+		if (is_raw_union && is_ordered) {
+			is_ordered = false;
+			syntax_error(token, "`#raw_union` cannot also be `#ordered`");
+		}
 
 		Token open = expect_token_after(f, Token_OpenBrace, "struct");
 
@@ -2481,7 +2480,7 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
 			decls = fields->FieldList.list;
 		}
 
-		return ast_struct_type(f, token, decls, name_count, polymorphic_params, is_packed, is_ordered, align);
+		return ast_struct_type(f, token, decls, name_count, polymorphic_params, is_packed, is_ordered, is_raw_union, align);
 	} break;
 
 	case Token_union: {
@@ -2510,23 +2509,6 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
 		return ast_union_type(f, token, variants);
 	} break;
 
-	case Token_raw_union: {
-		Token token = expect_token(f, Token_raw_union);
-		Token open = expect_token_after(f, Token_OpenBrace, "raw_union");
-
-		isize    decl_count = 0;
-		AstNode *fields     = parse_record_field_list(f, &decl_count);
-		Token    close      = expect_token(f, Token_CloseBrace);
-
-		Array<AstNode *> decls = {};
-		if (fields != nullptr) {
-			GB_ASSERT(fields->kind == AstNode_FieldList);
-			decls = fields->FieldList.list;
-		}
-
-		return ast_raw_union_type(f, token, decls, decl_count);
-	} break;
-
 	case Token_enum: {
 		Token token = expect_token(f, Token_enum);
 		AstNode *base_type = nullptr;

+ 1 - 1
src/ssa.cpp

@@ -652,7 +652,7 @@ bool can_ssa_type(Type *t) {
 		return false;
 
 	case Type_Record:
-		if (t->Record.kind == TypeRecord_Struct) {
+		if (!t->Record.is_raw_union) {
 			if (t->Record.field_count > SSA_MAX_STRUCT_FIELD_COUNT) {
 				return false;
 			}

+ 1 - 1
src/tokenizer.cpp

@@ -107,7 +107,7 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
 	TOKEN_KIND(Token_macro,                  "macro"),                  \
 	TOKEN_KIND(Token_struct,                 "struct"),                 \
 	TOKEN_KIND(Token_union,                  "union"),                  \
-	TOKEN_KIND(Token_raw_union,              "raw_union"),              \
+	/* TOKEN_KIND(Token_raw_union,              "raw_union"), */              \
 	TOKEN_KIND(Token_enum,                   "enum"),                   \
 	TOKEN_KIND(Token_bit_field,              "bit_field"),              \
 	TOKEN_KIND(Token_vector,                 "vector"),                 \

+ 81 - 113
src/types.cpp

@@ -68,17 +68,7 @@ struct BasicType {
 	String    name;
 };
 
-enum TypeRecordKind {
-	TypeRecord_Invalid,
-
-	TypeRecord_Struct,
-	TypeRecord_RawUnion,
-
-	TypeRecord_Count,
-};
-
 struct TypeRecord {
-	TypeRecordKind kind;
 
 	// All record types
 	// Theses are arrays
@@ -94,6 +84,7 @@ struct TypeRecord {
 	bool     are_offsets_being_processed;
 	bool     is_packed;
 	bool     is_ordered;
+	bool     is_raw_union;
 	bool     is_polymorphic;
 	bool     is_poly_specialized;
 	Type *   polymorphic_params; // Type_Tuple
@@ -523,7 +514,6 @@ Type *make_type_slice(gbAllocator a, Type *elem) {
 
 Type *make_type_struct(gbAllocator a) {
 	Type *t = alloc_type(a, Type_Record);
-	t->Record.kind = TypeRecord_Struct;
 	return t;
 }
 
@@ -532,12 +522,6 @@ Type *make_type_union(gbAllocator a) {
 	return t;
 }
 
-Type *make_type_raw_union(gbAllocator a) {
-	Type *t = alloc_type(a, Type_Record);
-	t->Record.kind = TypeRecord_RawUnion;
-	return t;
-}
-
 Type *make_type_enum(gbAllocator a) {
 	Type *t = alloc_type(a, Type_Enum);
 	return t;
@@ -847,7 +831,7 @@ Type *base_complex_elem_type(Type *t) {
 
 bool is_type_struct(Type *t) {
 	t = base_type(t);
-	return (t->kind == Type_Record && t->Record.kind == TypeRecord_Struct);
+	return (t->kind == Type_Record && !t->Record.is_raw_union);
 }
 bool is_type_union(Type *t) {
 	t = base_type(t);
@@ -856,7 +840,7 @@ bool is_type_union(Type *t) {
 
 bool is_type_raw_union(Type *t) {
 	t = base_type(t);
-	return (t->kind == Type_Record && t->Record.kind == TypeRecord_RawUnion);
+	return (t->kind == Type_Record && t->Record.is_raw_union);
 }
 bool is_type_enum(Type *t) {
 	t = base_type(t);
@@ -932,8 +916,7 @@ bool is_type_indexable(Type *t) {
 
 bool is_type_polymorphic_struct(Type *t) {
 	t = base_type(t);
-	if (t->kind == Type_Record &&
-	    t->Record.kind == TypeRecord_Struct) {
+	if (t->kind == Type_Record) {
 		return t->Record.is_polymorphic;
 	}
 	return false;
@@ -941,8 +924,7 @@ bool is_type_polymorphic_struct(Type *t) {
 
 bool is_type_polymorphic_struct_specialized(Type *t) {
 	t = base_type(t);
-	if (t->kind == Type_Record &&
-	    t->Record.kind == TypeRecord_Struct) {
+	if (t->kind == Type_Record) {
 		return t->Record.is_polymorphic && t->Record.is_poly_specialized;
 	}
 	return false;
@@ -1158,34 +1140,28 @@ bool are_types_identical(Type *x, Type *y) {
 
 	case Type_Record:
 		if (y->kind == Type_Record) {
-			if (x->Record.kind == y->Record.kind) {
-				switch (x->Record.kind) {
-				case TypeRecord_Struct:
-				case TypeRecord_RawUnion:
-					if (x->Record.field_count == y->Record.field_count &&
-					    x->Record.is_packed == y->Record.is_packed &&
-					    x->Record.is_ordered == y->Record.is_ordered &&
-					    x->Record.custom_align == y->Record.custom_align) {
-						// TODO(bill); Fix the custom alignment rule
-						for (isize i = 0; i < x->Record.field_count; i++) {
-							Entity *xf = x->Record.fields[i];
-							Entity *yf = y->Record.fields[i];
-							if (!are_types_identical(xf->type, yf->type)) {
-								return false;
-							}
-							if (xf->token.string != yf->token.string) {
-								return false;
-							}
-							bool xf_is_using = (xf->flags&EntityFlag_Using) != 0;
-							bool yf_is_using = (yf->flags&EntityFlag_Using) != 0;
-							if (xf_is_using ^ yf_is_using) {
-								return false;
-							}
-						}
-						return true;
+			if (x->Record.is_raw_union == y->Record.is_raw_union &&
+			    x->Record.field_count == y->Record.field_count &&
+			    x->Record.is_packed == y->Record.is_packed &&
+			    x->Record.is_ordered == y->Record.is_ordered &&
+			    x->Record.custom_align == y->Record.custom_align) {
+				// TODO(bill); Fix the custom alignment rule
+				for (isize i = 0; i < x->Record.field_count; i++) {
+					Entity *xf = x->Record.fields[i];
+					Entity *yf = y->Record.fields[i];
+					if (!are_types_identical(xf->type, yf->type)) {
+						return false;
+					}
+					if (xf->token.string != yf->token.string) {
+						return false;
+					}
+					bool xf_is_using = (xf->flags&EntityFlag_Using) != 0;
+					bool yf_is_using = (yf->flags&EntityFlag_Using) != 0;
+					if (xf_is_using ^ yf_is_using) {
+						return false;
 					}
-					break;
 				}
+				return true;
 			}
 		}
 		break;
@@ -1310,7 +1286,7 @@ bool is_type_cte_safe(Type *type) {
 		return false;
 
 	case Type_Record: {
-		if (type->Record.kind != TypeRecord_Struct) {
+		if (type->Record.is_raw_union) {
 			return false;
 		}
 		for (isize i = 0; i < type->Record.field_count; i++) {
@@ -1619,7 +1595,7 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
 			return lookup_field_with_selection(a, specialized, field_name, is_type, sel);
 		}
 
-	} else if (type->Record.kind == Type_Union) {
+	} else if (type->kind == Type_Union) {
 		if (field_name == "__tag") {
 			Entity *e = type->Union.union__tag;
 			GB_ASSERT(e != nullptr);
@@ -1868,8 +1844,22 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
 	} break;
 
 	case Type_Record: {
-		switch (t->Record.kind) {
-		case TypeRecord_Struct:
+		if (t->Record.is_raw_union) {
+			i64 max = 1;
+			for (isize i = 0; i < t->Record.field_count; i++) {
+				Type *field_type = t->Record.fields[i]->type;
+				type_path_push(path, field_type);
+				if (path->failure) {
+					return FAILURE_ALIGNMENT;
+				}
+				i64 align = type_align_of_internal(allocator, field_type, path);
+				type_path_pop(path);
+				if (max < align) {
+					max = align;
+				}
+			}
+			return max;
+		} else {
 			if (t->Record.custom_align > 0) {
 				return gb_clamp(t->Record.custom_align, 1, build_context.max_align);
 			}
@@ -1892,23 +1882,6 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
 				}
 				return max;
 			}
-			break;
-		case TypeRecord_RawUnion: {
-			i64 max = 1;
-			for (isize i = 0; i < t->Record.field_count; i++) {
-				Type *field_type = t->Record.fields[i]->type;
-				type_path_push(path, field_type);
-				if (path->failure) {
-					return FAILURE_ALIGNMENT;
-				}
-				i64 align = type_align_of_internal(allocator, field_type, path);
-				type_path_pop(path);
-				if (max < align) {
-					max = align;
-				}
-			}
-			return max;
-		} break;
 		}
 	} break;
 
@@ -1927,10 +1900,14 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
 	return gb_clamp(next_pow2(type_size_of_internal(allocator, t, path)), 1, build_context.word_size);
 }
 
-i64 *type_set_offsets_of(gbAllocator allocator, Entity **fields, isize field_count, bool is_packed) {
+i64 *type_set_offsets_of(gbAllocator allocator, Entity **fields, isize field_count, bool is_packed, bool is_raw_union) {
 	i64 *offsets = gb_alloc_array(allocator, i64, field_count);
 	i64 curr_offset = 0;
-	if (is_packed) {
+	if (is_raw_union) {
+		for (isize i = 0; i < field_count; i++) {
+			offsets[i] = 0;
+		}
+	} else if (is_packed) {
 		for (isize i = 0; i < field_count; i++) {
 			i64 size = type_size_of(allocator, fields[i]->type);
 			offsets[i] = curr_offset;
@@ -1950,17 +1927,17 @@ i64 *type_set_offsets_of(gbAllocator allocator, Entity **fields, isize field_cou
 
 bool type_set_offsets(gbAllocator allocator, Type *t) {
 	t = base_type(t);
-	if (is_type_struct(t)) {
+	if (t->kind == Type_Record) {
 		if (!t->Record.are_offsets_set) {
 			t->Record.are_offsets_being_processed = true;
-			t->Record.offsets = type_set_offsets_of(allocator, t->Record.fields, t->Record.field_count, t->Record.is_packed);
+			t->Record.offsets = type_set_offsets_of(allocator, t->Record.fields, t->Record.field_count, t->Record.is_packed, t->Record.is_raw_union);
 			t->Record.are_offsets_set = true;
 			return true;
 		}
 	} else if (is_type_tuple(t)) {
 		if (!t->Tuple.are_offsets_set) {
 			t->Record.are_offsets_being_processed = true;
-			t->Tuple.offsets = type_set_offsets_of(allocator, t->Tuple.variables, t->Tuple.variable_count, false);
+			t->Tuple.offsets = type_set_offsets_of(allocator, t->Tuple.variables, t->Tuple.variable_count, false, false);
 			t->Tuple.are_offsets_set = true;
 			return true;
 		}
@@ -2114,9 +2091,22 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
 
 
 	case Type_Record: {
-		switch (t->Record.kind) {
-
-		case TypeRecord_Struct: {
+		if (t->Record.is_raw_union) {
+			i64 count = t->Record.field_count;
+			i64 align = type_align_of_internal(allocator, t, path);
+			if (path->failure) {
+				return FAILURE_SIZE;
+			}
+			i64 max = 0;
+			for (isize i = 0; i < count; i++) {
+				i64 size = type_size_of_internal(allocator, t->Record.fields[i]->type, path);
+				if (max < size) {
+					max = size;
+				}
+			}
+			// TODO(bill): Is this how it should work?
+			return align_formula(max, align);
+		} else {
 			i64 count = t->Record.field_count;
 			if (count == 0) {
 				return 0;
@@ -2132,24 +2122,6 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
 			type_set_offsets(allocator, t);
 			i64 size = t->Record.offsets[count-1] + type_size_of_internal(allocator, t->Record.fields[count-1]->type, path);
 			return align_formula(size, align);
-		} break;
-
-		case TypeRecord_RawUnion: {
-			i64 count = t->Record.field_count;
-			i64 align = type_align_of_internal(allocator, t, path);
-			if (path->failure) {
-				return FAILURE_SIZE;
-			}
-			i64 max = 0;
-			for (isize i = 0; i < count; i++) {
-				i64 size = type_size_of_internal(allocator, t->Record.fields[i]->type, path);
-				if (max < size) {
-					max = size;
-				}
-			}
-			// TODO(bill): Is this how it should work?
-			return align_formula(max, align);
-		} break;
 		}
 	} break;
 
@@ -2172,7 +2144,7 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
 
 i64 type_offset_of(gbAllocator allocator, Type *t, i32 index) {
 	t = base_type(t);
-	if (t->kind == Type_Record && (t->Record.kind == TypeRecord_Struct)) {
+	if (t->kind == Type_Record && !t->Record.is_raw_union) {
 		type_set_offsets(allocator, t);
 		if (gb_is_between(index, 0, t->Record.field_count-1)) {
 			return t->Record.offsets[index];
@@ -2221,7 +2193,7 @@ i64 type_offset_of_from_selection(gbAllocator allocator, Type *type, Selection s
 		isize index = sel.index[i];
 		t = base_type(t);
 		offset += type_offset_of(allocator, t, index);
-		if (t->kind == Type_Record && t->Record.kind == TypeRecord_Struct) {
+		if (t->kind == Type_Record && !t->Record.is_raw_union) {
 			t = t->Record.fields[index]->type;
 		} else {
 			// NOTE(bill): No need to worry about custom types, just need the alignment
@@ -2339,16 +2311,8 @@ gbString write_type_to_string(gbString str, Type *type) {
 		break;
 
 	case Type_Record: {
-		switch (type->Record.kind) {
-		case TypeRecord_Struct:
-			str = gb_string_appendc(str, "struct");
-			if (type->Record.is_packed) {
-				str = gb_string_appendc(str, " #packed");
-			}
-			if (type->Record.is_ordered) {
-				str = gb_string_appendc(str, " #ordered");
-			}
-			str = gb_string_appendc(str, " {");
+		if (type->Record.is_raw_union) {
+			str = gb_string_appendc(str, "raw_union{");
 			for (isize i = 0; i < type->Record.field_count; i++) {
 				Entity *f = type->Record.fields[i];
 				GB_ASSERT(f->kind == Entity_Variable);
@@ -2360,10 +2324,15 @@ gbString write_type_to_string(gbString str, Type *type) {
 				str = write_type_to_string(str, f->type);
 			}
 			str = gb_string_appendc(str, "}");
-			break;
-
-		case TypeRecord_RawUnion:
-			str = gb_string_appendc(str, "raw_union{");
+		} else {
+			str = gb_string_appendc(str, "struct");
+			if (type->Record.is_packed) {
+				str = gb_string_appendc(str, " #packed");
+			}
+			if (type->Record.is_ordered) {
+				str = gb_string_appendc(str, " #ordered");
+			}
+			str = gb_string_appendc(str, " {");
 			for (isize i = 0; i < type->Record.field_count; i++) {
 				Entity *f = type->Record.fields[i];
 				GB_ASSERT(f->kind == Entity_Variable);
@@ -2375,7 +2344,6 @@ gbString write_type_to_string(gbString str, Type *type) {
 				str = write_type_to_string(str, f->type);
 			}
 			str = gb_string_appendc(str, "}");
-			break;
 		}
 	} break;