aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgingerBill <gingerBill@users.noreply.github.com>2025-09-29 10:28:16 +0100
committergingerBill <gingerBill@users.noreply.github.com>2025-09-29 10:28:16 +0100
commit10ba956d6a57cb5b334b4311cda96c6c7f8737db (patch)
tree6276240a0153e407ce7e2c21133f95fc3bc02913
parent1f2cedcf78907c7cb2d743cc476f11981a06e32b (diff)
Rudimentary support for some constant `struct #raw_union`
-rw-r--r--src/check_expr.cpp2
-rw-r--r--src/llvm_backend_const.cpp33
-rw-r--r--src/types.cpp18
3 files changed, 50 insertions, 3 deletions
diff --git a/src/check_expr.cpp b/src/check_expr.cpp
index 10fec1890..02cd66136 100644
--- a/src/check_expr.cpp
+++ b/src/check_expr.cpp
@@ -9847,7 +9847,7 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
if (t->Struct.is_raw_union) {
if (cl->elems.count > 0) {
// NOTE: unions cannot be constant
- is_constant = false;
+ is_constant = elem_type_can_be_constant(t);
if (cl->elems[0]->kind != Ast_FieldValue) {
gbString type_str = type_to_string(type);
diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp
index ebafa488e..782c75cd2 100644
--- a/src/llvm_backend_const.cpp
+++ b/src/llvm_backend_const.cpp
@@ -1475,6 +1475,39 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
}
if (is_type_raw_union(type)) {
+ if (is_type_raw_union_constantable(type)) {
+ GB_ASSERT(cl->elems.count == 1);
+ GB_ASSERT(cl->elems[0]->kind == Ast_FieldValue);
+ ast_node(fv, FieldValue, cl->elems[0]);
+ Entity *f = entity_of_node(fv->field);
+
+ TypeAndValue tav = fv->value->tav;
+ if (tav.value.kind != ExactValue_Invalid) {
+ lbValue value = lb_const_value(m, f->type, tav.value, cc, f->type);
+
+ LLVMValueRef values[2];
+ unsigned value_count = 0;
+
+ values[value_count++] = value.value;
+
+ i64 union_alignment = type_align_of(type);
+ i64 value_alignment = type_align_of(f->type);
+ i64 alignment = gb_max(gb_min(value_alignment, union_alignment), 1);
+
+ i64 union_size = type_size_of(type);
+ i64 value_size = lb_sizeof(LLVMTypeOf(value.value));
+ i64 padding = union_size-value_size;
+ if (padding > 0) {
+ LLVMTypeRef padding_type = lb_type_padding_filler(m, padding, alignment);
+ values[value_count++] = LLVMConstNull(padding_type);
+ }
+
+ LLVMValueRef res = LLVMConstStructInContext(m->ctx, values, value_count, true);
+
+ return {res, original_type};
+ }
+
+ }
return lb_const_nil(m, original_type);
}
diff --git a/src/types.cpp b/src/types.cpp
index 62e47259d..1fbcd429b 100644
--- a/src/types.cpp
+++ b/src/types.cpp
@@ -2531,6 +2531,20 @@ gb_internal bool is_type_union_constantable(Type *type) {
return true;
}
+gb_internal bool is_type_raw_union_constantable(Type *type) {
+ Type *bt = base_type(type);
+ GB_ASSERT(bt->kind == Type_Struct);
+ GB_ASSERT(bt->Struct.is_raw_union);
+
+ for (Entity *f : bt->Struct.fields) {
+ if (!is_type_constant_type(f->type)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+
gb_internal bool elem_type_can_be_constant(Type *t) {
t = base_type(t);
if (t == t_invalid) {
@@ -2540,7 +2554,7 @@ gb_internal bool elem_type_can_be_constant(Type *t) {
return false;
}
if (is_type_raw_union(t)) {
- return false;
+ return is_type_raw_union_constantable(t);
}
if (is_type_union(t)) {
return is_type_union_constantable(t);
@@ -2556,7 +2570,7 @@ gb_internal bool elem_cannot_be_constant(Type *t) {
return !is_type_union_constantable(t);
}
if (is_type_raw_union(t)) {
- return true;
+ return !is_type_raw_union_constantable(t);
}
return false;
}