From f99baf479e3a8f81f117a6716a4caa0a51e48168 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Sun, 9 Jun 2024 16:51:32 +0200 Subject: [PATCH] Compiler crash using enum nameof from different module #1205. --- releasenotes.md | 3 +- src/compiler/llvm_codegen_expr.c | 3 +- .../generic/enum_in_other_module.c3t | 104 ++++++++++++++++++ 3 files changed, 107 insertions(+), 3 deletions(-) create mode 100644 test/test_suite/generic/enum_in_other_module.c3t diff --git a/releasenotes.md b/releasenotes.md index 7a22a9d27..3a10225e6 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -32,7 +32,8 @@ - Bug when assigning an optional from an optional. - Lambdas were not type checked thoroughly #1185. - Fix problems using reflection on interface types #1203. -- `@param` with unnamed macro varargs could crash the compiler. +- `@param` with unnamed macro varargs could crash the compiler. +- Compiler crash using enum nameof from different module #1205. ### Stdlib changes - "init_new/init_temp" removed. diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index 379c903f3..c2305edaf 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -6760,8 +6760,7 @@ static inline void llvm_emit_builtin_access(GenContext *c, BEValue *be_value, Ex assert(inner_type->canonical->type_kind == TYPE_ENUM); llvm_value_rvalue(c, be_value); LLVMTypeRef slice = llvm_get_type(c, type_chars); - - LLVMValueRef to_introspect = LLVMBuildIntToPtr(c->builder, inner_type->backend_typeid, + LLVMValueRef to_introspect = LLVMBuildIntToPtr(c->builder, llvm_get_typeid(c, inner_type), c->ptr_type, ""); LLVMValueRef ptr = LLVMBuildStructGEP2(c->builder, c->introspect_type, to_introspect, INTROSPECT_INDEX_ADDITIONAL, ""); LLVMValueRef val = llvm_zext_trunc(c, be_value->value, c->size_type); diff --git a/test/test_suite/generic/enum_in_other_module.c3t b/test/test_suite/generic/enum_in_other_module.c3t new file mode 100644 index 000000000..45dcf3e15 --- /dev/null +++ b/test/test_suite/generic/enum_in_other_module.c3t @@ -0,0 +1,104 @@ +// #target: macos-x64 +module test; +import foo; + +fn int main(String[] args) { + foo::bar(ONE); + return 0; +} + +enum Enum : int {ONE, TWO, THREE} + +module foo; +import std; +import test; + +fn void bar(Enum e) { + io::printn(e.nameof); +} + +/* #expect: foo.ll + +@.enum.ONE = internal constant [4 x i8] c"ONE\00", align 1 +@.enum.TWO = internal constant [4 x i8] c"TWO\00", align 1 +@.enum.THREE = internal constant [6 x i8] c"THREE\00", align 1 +@"$ct.int" = linkonce global %.introspect { i8 2, i64 0, ptr null, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8 +@"$ct.test.Enum" = linkonce global { i8, i64, ptr, i64, i64, i64, [3 x %"char[]"] } { i8 8, i64 0, ptr null, i64 4, i64 ptrtoint (ptr @"$ct.int" to i64), i64 3, [3 x %"char[]"] [%"char[]" { ptr @.enum.ONE, i64 3 }, %"char[]" { ptr @.enum.TWO, i64 3 }, %"char[]" { ptr @.enum.THREE, i64 5 }] }, align 8 + +; Function Attrs: nounwind uwtable +define void @foo.bar(i32 %0) #0 { +entry: + %x = alloca %"char[]", align 8 + %x1 = alloca %"char[]", align 8 + %len = alloca i64, align 8 + %error_var = alloca i64, align 8 + %x2 = alloca %"char[]", align 8 + %retparam = alloca i64, align 8 + %error_var4 = alloca i64, align 8 + %error_var10 = alloca i64, align 8 + %zext = zext i32 %0 to i64 + %ptroffset_any = getelementptr [16 x i8], ptr getelementptr inbounds (%.introspect, ptr @"$ct.test.Enum", i32 0, i32 6), i64 %zext + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %x, ptr align 8 %ptroffset_any, i32 16, i1 false) + %1 = call ptr @std.io.stdout() + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %x1, ptr align 8 %x, i32 16, i1 false) + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %x2, ptr align 8 %x1, i32 16, i1 false) + %lo = load ptr, ptr %x2, align 8 + %ptradd = getelementptr inbounds i8, ptr %x2, i64 8 + %hi = load i64, ptr %ptradd, align 8 + %2 = call i64 @std.io.File.write(ptr %retparam, ptr %1, ptr %lo, i64 %hi) + %not_err = icmp eq i64 %2, 0 + %3 = call i1 @llvm.expect.i1(i1 %not_err, i1 true) + br i1 %3, label %after_check, label %assign_optional + +assign_optional: ; preds = %entry + store i64 %2, ptr %error_var, align 8 + br label %guard_block + +after_check: ; preds = %entry + br label %noerr_block + +guard_block: ; preds = %assign_optional + br label %voiderr + +noerr_block: ; preds = %after_check + %4 = load i64, ptr %retparam, align 8 + store i64 %4, ptr %len, align 8 + %5 = call i64 @std.io.File.write_byte(ptr %1, i8 zeroext 10) + %not_err5 = icmp eq i64 %5, 0 + %6 = call i1 @llvm.expect.i1(i1 %not_err5, i1 true) + br i1 %6, label %after_check7, label %assign_optional6 + +assign_optional6: ; preds = %noerr_block + store i64 %5, ptr %error_var4, align 8 + br label %guard_block8 + +after_check7: ; preds = %noerr_block + br label %noerr_block9 + +guard_block8: ; preds = %assign_optional6 + br label %voiderr + +noerr_block9: ; preds = %after_check7 + %7 = call i64 @std.io.File.flush(ptr %1) + %not_err11 = icmp eq i64 %7, 0 + %8 = call i1 @llvm.expect.i1(i1 %not_err11, i1 true) + br i1 %8, label %after_check13, label %assign_optional12 + +assign_optional12: ; preds = %noerr_block9 + store i64 %7, ptr %error_var10, align 8 + br label %guard_block14 + +after_check13: ; preds = %noerr_block9 + br label %noerr_block15 + +guard_block14: ; preds = %assign_optional12 + br label %voiderr + +noerr_block15: ; preds = %after_check13 + %9 = load i64, ptr %len, align 8 + %add = add i64 %9, 1 + br label %voiderr + +voiderr: ; preds = %noerr_block15, %guard_block14, %guard_block8, %guard_block + ret void +} \ No newline at end of file