diff --git a/releasenotes.md b/releasenotes.md index 09d121fb8..9682586b7 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -45,6 +45,7 @@ - Issue where a `if (catch e = ...)` in a defer would be incorrectly copied. Causing codegen error. - Variable in if-try / if-catch cannot be a reused variable name. - Vararg interfaces were broken. +- LLVM codegen for constants in enums could fail. ### Stdlib changes diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index f3e4fc7a0..62ebfd999 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -402,7 +402,7 @@ LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_ case CONST_INIT_VALUE: { BEValue value; - llvm_emit_expr(c, &value, const_init->init_value); + llvm_emit_expr_global_value(c, &value, const_init->init_value); return llvm_load_value_store(c, &value); } } @@ -497,7 +497,7 @@ void llvm_emit_global_variable_init(GenContext *c, Decl *decl) else { BEValue value; - llvm_emit_expr(c, &value, init_expr); + llvm_emit_expr_global_value(c, &value, init_expr); init_value = llvm_load_value_store(c, &value); } } @@ -558,7 +558,7 @@ void llvm_emit_global_variable_init(GenContext *c, Decl *decl) Expr *inner = init_expr->inner_expr; assert(expr_is_const(inner) && inner->const_expr.const_kind == CONST_ERR); BEValue value; - llvm_emit_expr(c, &value, inner); + llvm_emit_expr_global_value(c, &value, inner); optional_value = llvm_load_value_store(c, &value); } if (!decl->is_extern) diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index f49505013..73bfdf7f5 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -7043,6 +7043,12 @@ static void llvm_emit_default_arg(GenContext *c, BEValue *value, Expr *expr) } } +void llvm_emit_expr_global_value(GenContext *c, BEValue *value, Expr *expr) +{ + sema_cast_const(expr); + llvm_emit_expr(c, value, expr); + assert(!llvm_value_is_addr(value)); +} void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr) { EMIT_LOC(c, expr); diff --git a/src/compiler/llvm_codegen_internal.h b/src/compiler/llvm_codegen_internal.h index 6cdbda8c6..3ec9c5e5f 100644 --- a/src/compiler/llvm_codegen_internal.h +++ b/src/compiler/llvm_codegen_internal.h @@ -502,6 +502,7 @@ void llvm_emit_parameter(GenContext *c, LLVMValueRef *args, unsigned *arg_count_ LLVMValueRef llvm_get_selector(GenContext *c, const char *name); // -- C3 Lowering -- +void llvm_emit_expr_global_value(GenContext *c, BEValue *value, Expr *expr); void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr); LLVMValueRef llvm_emit_expr_to_rvalue(GenContext *c, Expr *expr); LLVMValueRef llvm_emit_exprid_to_rvalue(GenContext *c, ExprId expr_id); diff --git a/src/compiler/llvm_codegen_type.c b/src/compiler/llvm_codegen_type.c index 8fc0b22ad..b972782ed 100644 --- a/src/compiler/llvm_codegen_type.c +++ b/src/compiler/llvm_codegen_type.c @@ -538,10 +538,8 @@ static LLVMValueRef llvm_get_introspection_for_enum(GenContext *c, Type *type) for (unsigned i = 0; i < elements; i++) { BEValue value; - llvm_emit_expr(c, &value, enum_vals[i]->enum_constant.args[ai]); - assert(!llvm_value_is_addr(&value)); - LLVMValueRef llvm_value = llvm_value_is_bool(&value) ? LLVMBuildZExt(c->builder, value.value, c->byte_type, "") - : value.value; + llvm_emit_expr_global_value(c, &value, enum_vals[i]->enum_constant.args[ai]); + LLVMValueRef llvm_value = llvm_load_value_store(c, &value); values[i] = llvm_value; if (!val_type) { diff --git a/test/test_suite/enumerations/enum_with_const.c3t b/test/test_suite/enumerations/enum_with_const.c3t new file mode 100644 index 000000000..3474872a7 --- /dev/null +++ b/test/test_suite/enumerations/enum_with_const.c3t @@ -0,0 +1,55 @@ +// #target: macos-x64 +module test; + +const FG_YELLOW = "\e[0;38;2;255;240;128m"; +const FG_GREEN = "\e[0;38;2;192;255;192m"; +const FG_RED = "\e[0;38;2;255;40;40m"; + +enum SeverityTag : int (String fg, String label) { + INFO = { FG_GREEN, "info" }, + WARN = { FG_YELLOW, "warn" }, + FATAL = { FG_RED, "fatal" }, + FATAL2 = { FG_RED, "fatal2" }, +} + +fn void main() +{ + SeverityTag tag = WARN; + String a = tag.fg; +} + +/* #expect: test.ll + +@.enum.INFO = internal constant [5 x i8] c"INFO\00", align 1 +@.enum.WARN = internal constant [5 x i8] c"WARN\00", align 1 +@.enum.FATAL = internal constant [6 x i8] c"FATAL\00", align 1 +@.enum.FATAL2 = internal constant [7 x i8] c"FATAL2\00", align 1 +@"$ct.test.SeverityTag" = linkonce global { i8, i64, ptr, i64, i64, i64, [4 x %"char[]"] } { i8 8, i64 0, ptr null, i64 4, i64 ptrtoint (ptr @"$ct.int" to i64), i64 4, [4 x %"char[]"] [%"char[]" { ptr @.enum.INFO, i64 4 }, %"char[]" { ptr @.enum.WARN, i64 4 }, %"char[]" { ptr @.enum.FATAL, i64 5 }, %"char[]" { ptr @.enum.FATAL2, i64 6 }] }, align 8 +@.str = private unnamed_addr constant [22 x i8] c"\1B[0;38;2;192;255;192m\00", align 1 +@.str.1 = private unnamed_addr constant [22 x i8] c"\1B[0;38;2;255;240;128m\00", align 1 +@.str.2 = private unnamed_addr constant [20 x i8] c"\1B[0;38;2;255;40;40m\00", align 1 +@.str.3 = private unnamed_addr constant [20 x i8] c"\1B[0;38;2;255;40;40m\00", align 1 +@"test.SeverityTag$fg" = linkonce constant [4 x %"char[]"] [%"char[]" { ptr @.str, i64 21 }, %"char[]" { ptr @.str.1, i64 21 }, %"char[]" { ptr @.str.2, i64 19 }, %"char[]" { ptr @.str.3, i64 19 }], align 8 +@.str.4 = private unnamed_addr constant [5 x i8] c"info\00", align 1 +@.str.5 = private unnamed_addr constant [5 x i8] c"warn\00", align 1 +@.str.6 = private unnamed_addr constant [6 x i8] c"fatal\00", align 1 +@.str.7 = private unnamed_addr constant [7 x i8] c"fatal2\00", align 1 +@"test.SeverityTag$label" = linkonce constant [4 x %"char[]"] [%"char[]" { ptr @.str.4, i64 4 }, %"char[]" { ptr @.str.5, i64 4 }, %"char[]" { ptr @.str.6, i64 5 }, %"char[]" { ptr @.str.7, i64 6 }], align 8 +@.str.10 = private unnamed_addr constant [22 x i8] c"\1B[0;38;2;255;240;128m\00", align 1 +@test.FG_YELLOW = local_unnamed_addr constant %"char[]" { ptr @.str.10, i64 21 }, align 8 +@.str.11 = private unnamed_addr constant [22 x i8] c"\1B[0;38;2;192;255;192m\00", align 1 +@test.FG_GREEN = local_unnamed_addr constant %"char[]" { ptr @.str.11, i64 21 }, align 8 +@.str.12 = private unnamed_addr constant [20 x i8] c"\1B[0;38;2;255;40;40m\00", align 1 +@test.FG_RED = local_unnamed_addr constant %"char[]" { ptr @.str.12, i64 19 }, align 8 + +define void @test.main() #0 { +entry: + %tag = alloca i32, align 4 + %a = alloca %"char[]", align 8 + store i32 1, ptr %tag, align 4 + %0 = load i32, ptr %tag, align 4 + %ptroffset = getelementptr inbounds [16 x i8], ptr @"test.SeverityTag$fg", i32 %0 + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %a, ptr align 8 %ptroffset, i32 16, i1 false) + ret void +} +