From 10ba956d6a57cb5b334b4311cda96c6c7f8737db Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 29 Sep 2025 10:28:16 +0100 Subject: Rudimentary support for some constant `struct #raw_union` --- src/check_expr.cpp | 2 +- src/llvm_backend_const.cpp | 33 +++++++++++++++++++++++++++++++++ src/types.cpp | 18 ++++++++++++++++-- 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; } -- cgit v1.2.3