From 26d25e3f74c08e0ef55dec12392bad26ba294835 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Sun, 24 Jan 2021 22:53:46 +0100 Subject: [PATCH] Recursive references between globals are now correctly handled. --- resources/examples/base64.c3 | 5 +- .../{ => notworking}/acornvm/avm_array.c3 | 0 .../{ => notworking}/acornvm/avm_memory.c3 | 0 .../{ => notworking}/acornvm/avm_stack.c3 | 0 .../examples/{ => notworking}/acornvm/gen.c3 | 0 .../{ => notworking}/acornvm/lexer.c3 | 0 .../examples/{ => notworking}/acornvm/main.c3 | 0 .../{ => notworking}/acornvm/parser.c3 | 0 .../{ => notworking}/acornvm/parser_ast.c3 | 0 .../{ => notworking}/acornvm/symbol.c3 | 0 .../{ => notworking}/acornvm/typ_all.c3 | 0 .../{ => notworking}/acornvm/types.c3 | 0 .../{ => notworking}/acornvm/value.c3 | 0 .../examples/{ => notworking}/acornvm/vm.c3 | 0 resources/lib/std/cinterop.c3 | 1 + resources/testfragments/simple_test1.c3 | 27 ------- resources/testfragments/simple_test2.c3 | 13 ---- resources/testfragments/struct_ref.c3 | 51 ------------- resources/testfragments/structo.c3 | 18 ----- resources/tests/typedef_errors.c3 | 5 -- resources/tests/typedefs_ok.c3 | 14 ---- src/compiler/llvm_codegen.c | 19 +++++ src/compiler/sema_decls.c | 72 ++++++++++--------- src/compiler/sema_expr.c | 1 + test/test_suite/globals/recursive_locals.c3 | 12 ++++ 25 files changed, 75 insertions(+), 163 deletions(-) rename resources/examples/{ => notworking}/acornvm/avm_array.c3 (100%) rename resources/examples/{ => notworking}/acornvm/avm_memory.c3 (100%) rename resources/examples/{ => notworking}/acornvm/avm_stack.c3 (100%) rename resources/examples/{ => notworking}/acornvm/gen.c3 (100%) rename resources/examples/{ => notworking}/acornvm/lexer.c3 (100%) rename resources/examples/{ => notworking}/acornvm/main.c3 (100%) rename resources/examples/{ => notworking}/acornvm/parser.c3 (100%) rename resources/examples/{ => notworking}/acornvm/parser_ast.c3 (100%) rename resources/examples/{ => notworking}/acornvm/symbol.c3 (100%) rename resources/examples/{ => notworking}/acornvm/typ_all.c3 (100%) rename resources/examples/{ => notworking}/acornvm/types.c3 (100%) rename resources/examples/{ => notworking}/acornvm/value.c3 (100%) rename resources/examples/{ => notworking}/acornvm/vm.c3 (100%) delete mode 100644 resources/testfragments/simple_test1.c3 delete mode 100644 resources/testfragments/simple_test2.c3 delete mode 100644 resources/testfragments/struct_ref.c3 delete mode 100644 resources/testfragments/structo.c3 delete mode 100644 resources/tests/typedef_errors.c3 delete mode 100644 resources/tests/typedefs_ok.c3 create mode 100644 test/test_suite/globals/recursive_locals.c3 diff --git a/resources/examples/base64.c3 b/resources/examples/base64.c3 index 5d0f9203f..1dcc6f87b 100644 --- a/resources/examples/base64.c3 +++ b/resources/examples/base64.c3 @@ -115,15 +115,14 @@ public func int! decode(char[] in, byte* out) } extern func void printf(char *fmt, ...); + public func void main() { - printf("Startin...\n"); char *helloworld = "Hello World\n"; char[1000] buffer; encode(cast(helloworld as byte*)[0..12], &buffer); - printf("Printres\n"); printf("Result: %s\n", &buffer); char *to_decode = "aGVsbG8gd29ybGRcMA=="; decode(to_decode[0..19], cast(&buffer as byte*)); - printf("2Result: %s\n", &buffer); + printf("Result: %s\n", &buffer); } \ No newline at end of file diff --git a/resources/examples/acornvm/avm_array.c3 b/resources/examples/notworking/acornvm/avm_array.c3 similarity index 100% rename from resources/examples/acornvm/avm_array.c3 rename to resources/examples/notworking/acornvm/avm_array.c3 diff --git a/resources/examples/acornvm/avm_memory.c3 b/resources/examples/notworking/acornvm/avm_memory.c3 similarity index 100% rename from resources/examples/acornvm/avm_memory.c3 rename to resources/examples/notworking/acornvm/avm_memory.c3 diff --git a/resources/examples/acornvm/avm_stack.c3 b/resources/examples/notworking/acornvm/avm_stack.c3 similarity index 100% rename from resources/examples/acornvm/avm_stack.c3 rename to resources/examples/notworking/acornvm/avm_stack.c3 diff --git a/resources/examples/acornvm/gen.c3 b/resources/examples/notworking/acornvm/gen.c3 similarity index 100% rename from resources/examples/acornvm/gen.c3 rename to resources/examples/notworking/acornvm/gen.c3 diff --git a/resources/examples/acornvm/lexer.c3 b/resources/examples/notworking/acornvm/lexer.c3 similarity index 100% rename from resources/examples/acornvm/lexer.c3 rename to resources/examples/notworking/acornvm/lexer.c3 diff --git a/resources/examples/acornvm/main.c3 b/resources/examples/notworking/acornvm/main.c3 similarity index 100% rename from resources/examples/acornvm/main.c3 rename to resources/examples/notworking/acornvm/main.c3 diff --git a/resources/examples/acornvm/parser.c3 b/resources/examples/notworking/acornvm/parser.c3 similarity index 100% rename from resources/examples/acornvm/parser.c3 rename to resources/examples/notworking/acornvm/parser.c3 diff --git a/resources/examples/acornvm/parser_ast.c3 b/resources/examples/notworking/acornvm/parser_ast.c3 similarity index 100% rename from resources/examples/acornvm/parser_ast.c3 rename to resources/examples/notworking/acornvm/parser_ast.c3 diff --git a/resources/examples/acornvm/symbol.c3 b/resources/examples/notworking/acornvm/symbol.c3 similarity index 100% rename from resources/examples/acornvm/symbol.c3 rename to resources/examples/notworking/acornvm/symbol.c3 diff --git a/resources/examples/acornvm/typ_all.c3 b/resources/examples/notworking/acornvm/typ_all.c3 similarity index 100% rename from resources/examples/acornvm/typ_all.c3 rename to resources/examples/notworking/acornvm/typ_all.c3 diff --git a/resources/examples/acornvm/types.c3 b/resources/examples/notworking/acornvm/types.c3 similarity index 100% rename from resources/examples/acornvm/types.c3 rename to resources/examples/notworking/acornvm/types.c3 diff --git a/resources/examples/acornvm/value.c3 b/resources/examples/notworking/acornvm/value.c3 similarity index 100% rename from resources/examples/acornvm/value.c3 rename to resources/examples/notworking/acornvm/value.c3 diff --git a/resources/examples/acornvm/vm.c3 b/resources/examples/notworking/acornvm/vm.c3 similarity index 100% rename from resources/examples/acornvm/vm.c3 rename to resources/examples/notworking/acornvm/vm.c3 diff --git a/resources/lib/std/cinterop.c3 b/resources/lib/std/cinterop.c3 index a50113e77..a8aa8bf84 100644 --- a/resources/lib/std/cinterop.c3 +++ b/resources/lib/std/cinterop.c3 @@ -1,2 +1,3 @@ module std:cinterop; + diff --git a/resources/testfragments/simple_test1.c3 b/resources/testfragments/simple_test1.c3 deleted file mode 100644 index 14806d1ea..000000000 --- a/resources/testfragments/simple_test1.c3 +++ /dev/null @@ -1,27 +0,0 @@ -module foo; - -public struct Foo -{ - int i; -} - -public func int Foo.test(Foo *foo) -{ - if (!foo) return 0; - return foo.i; -} - -public func void gonk() -{ - Foo.test(null); - printf("Bob\n"); -} -func void test() -{ - int i = 0; -} - -func void main() -{ - printf("Helo\n"); -} \ No newline at end of file diff --git a/resources/testfragments/simple_test2.c3 b/resources/testfragments/simple_test2.c3 deleted file mode 100644 index 7ab2beac0..000000000 --- a/resources/testfragments/simple_test2.c3 +++ /dev/null @@ -1,13 +0,0 @@ -module bar; -import foo local; - -func void test() -{ - int i = 0; -} - -func void main() -{ - gonk(); - printf("Helo\n"); -} \ No newline at end of file diff --git a/resources/testfragments/struct_ref.c3 b/resources/testfragments/struct_ref.c3 deleted file mode 100644 index 0976f701c..000000000 --- a/resources/testfragments/struct_ref.c3 +++ /dev/null @@ -1,51 +0,0 @@ -struct Foo -{ - int x; - struct b - { - int y; - int z; - } - struct - { - int g; - } - union - { - usize x1; - int z2; - } -} - -func void Foo.xy(Foo* f, int y) -{ - f.b.y = y; -} - -extern func void printf(char*c , ...); - -struct SimpleStruct -{ - int a; - double b; -} -func void main() -{ - Foo z; - z.x = 2; - z.b.z = 3; - z.g = 4; - printf("z.x = %d\n", z.x); - printf("z.b.z = %d\n", z.b.z); - printf("z.g = %d\n", z.g); - z.xy(100); - printf("z.b.y = %d\n", z.b.y); - SimpleStruct s = { a = 3, b = 33.3 }; - int[2] fe = { 1, 2 }; - //Foo f = { x = 2, b.z = 3, z2 = -2 }; - Foo f = { x = 2, b.z = 3, z2 = -2, b = { 1, 4 } }; - int[3] fo = { [1] = 2 }; - - - //byte[7] fo = { [1..4] = 3 }; -} \ No newline at end of file diff --git a/resources/testfragments/structo.c3 b/resources/testfragments/structo.c3 deleted file mode 100644 index 4fd582b14..000000000 --- a/resources/testfragments/structo.c3 +++ /dev/null @@ -1,18 +0,0 @@ -module struct2; - -struct Blend_Map_Entry -{ - union vals { - float[5] colour; - double[2] point_Slope; - } -} - -Blend_Map_Entry a = { .vals = { .colour = { 1, 2, 3, 4, 5 } } }; -Blend_Map_Entry b = { .vals = { .point_Slope = { 6, 7 } } }; -Blend_Map_Entry c = { .vals.colour[2] = 1 }; -Blend_Map_Entry d = { .vals.colour = { 1, 2, 3, 4, 5 } }; - -func void test(Blend_Map_Entry* foo) -{ -} \ No newline at end of file diff --git a/resources/tests/typedef_errors.c3 b/resources/tests/typedef_errors.c3 deleted file mode 100644 index 49180f6d2..000000000 --- a/resources/tests/typedef_errors.c3 +++ /dev/null @@ -1,5 +0,0 @@ -module typedefs; - -typedef Loop as Loop2; -typedef Loop2 as Loop3; -typedef Loop3 as Loop; diff --git a/resources/tests/typedefs_ok.c3 b/resources/tests/typedefs_ok.c3 deleted file mode 100644 index c1a2c397e..000000000 --- a/resources/tests/typedefs_ok.c3 +++ /dev/null @@ -1,14 +0,0 @@ -module typedefs; - -// Standard case -typedef int as Foo; - -// Nested resolution -typedef AType as BType; -typedef int as AType; - -enum Bar : BType -{ - A, - B -} diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index 92b35ff3e..5aff818d0 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -291,10 +291,22 @@ static void gencontext_emit_global_variable_definition(GenContext *c, Decl *decl // Skip real constants. if (!decl->type) return; + decl->backend_ref = LLVMAddGlobal(c->module, llvm_get_type(c, decl->type), "tempglobal"); + +} + +static void gencontext_emit_global_variable_init(GenContext *c, Decl *decl) +{ + assert(decl->var.kind == VARDECL_GLOBAL || decl->var.kind == VARDECL_CONST); + + // Skip real constants. + if (!decl->type) return; + bool modified = false; LLVMValueRef init_value; ByteSize alignment = type_abi_alignment(decl->type); + if (decl->var.init_expr) { if (decl->var.init_expr->expr_kind == EXPR_INITIALIZER_LIST) @@ -315,6 +327,7 @@ static void gencontext_emit_global_variable_definition(GenContext *c, Decl *decl } // TODO fix name + LLVMValueRef old = decl->backend_ref; decl->backend_ref = LLVMAddGlobal(c->module, LLVMTypeOf(init_value), decl->name); LLVMSetAlignment(decl->backend_ref, alignment); if (decl->visibility != VISIBLE_EXTERN) @@ -345,6 +358,8 @@ static void gencontext_emit_global_variable_definition(GenContext *c, Decl *decl { decl->backend_ref = LLVMConstBitCast(decl->backend_ref, llvm_get_ptr_type(c, decl->type)); } + LLVMReplaceAllUsesWith(old, decl->backend_ref); + // Should we set linkage here? if (llvm_use_debug(c)) { @@ -880,6 +895,10 @@ void *llvm_gen(Context *context) { gencontext_emit_global_variable_definition(gen_context, context->vars[i]); } + VECEACH(context->vars, i) + { + gencontext_emit_global_variable_init(gen_context, context->vars[i]); + } VECEACH(context->functions, i) { Decl *decl = context->functions[i]; diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index 0c488b52f..1d5e62994 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -807,38 +807,7 @@ static inline bool sema_analyse_global(Context *context, Decl *decl) if (!sema_resolve_type_info(context, decl->var.type_info)) return false; decl->type = decl->var.type_info->type; } - // Check the initializer. - if (decl->var.init_expr && decl->type) - { - Expr *init_expr = decl->var.init_expr; - // 1. Check type. - if (!sema_analyse_expr_of_required_type(context, decl->type, init_expr, false)) return false; - // 2. Check const-ness - if (!init_expr->constant) - { - // 3. Special case is when the init expression is the reference - // to a constant global structure. - if (init_expr->expr_kind == EXPR_CONST_IDENTIFIER) - { - // 4. If so we copy the init expression, which should always be constant. - *init_expr = *init_expr->identifier_expr.decl->var.init_expr; - assert(init_expr->constant); - } - else - { - if (init_expr->expr_kind == EXPR_CAST) - { - SEMA_ERROR(decl->var.init_expr, "The expression may not be a non constant cast."); - } - else - { - SEMA_ERROR(decl->var.init_expr, "The expression must be a constant value."); - } - return false; - } - } - if (!decl->type) decl->type = decl->var.init_expr->type; - } + // We expect a constant to actually be parsed correctly so that it has a value, so // this should always be true. assert(decl->type || decl->var.kind == VARDECL_CONST); @@ -879,6 +848,45 @@ static inline bool sema_analyse_global(Context *context, Decl *decl) } } + // If we already have the type resolved then we can pretend to be done, + // this will help in case we otherwise would get circular references. + if (decl->type) + { + decl->resolve_status = RESOLVE_DONE; + } + + // Check the initializer. + if (decl->var.init_expr && decl->type) + { + Expr *init_expr = decl->var.init_expr; + // 1. Check type. + if (!sema_analyse_expr_of_required_type(context, decl->type, init_expr, false)) return false; + // 2. Check const-ness + if (!init_expr->constant) + { + // 3. Special case is when the init expression is the reference + // to a constant global structure. + if (init_expr->expr_kind == EXPR_CONST_IDENTIFIER) + { + // 4. If so we copy the init expression, which should always be constant. + *init_expr = *init_expr->identifier_expr.decl->var.init_expr; + assert(init_expr->constant); + } + else + { + if (init_expr->expr_kind == EXPR_CAST) + { + SEMA_ERROR(decl->var.init_expr, "The expression may not be a non constant cast."); + } + else + { + SEMA_ERROR(decl->var.init_expr, "The expression must be a constant value."); + } + return false; + } + } + } + switch (decl->var.kind) { case VARDECL_CONST: diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index b26a1d94c..e75b419c2 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -4011,6 +4011,7 @@ static inline bool sema_take_addr_of_var(Expr *expr, Decl *decl, bool *is_consta case VARDECL_PARAM_REF: return true; case VARDECL_CONST: + *is_constant = true; if (!decl->var.type_info) { SEMA_ERROR(expr, "The constant is not typed, either type it or use && to take the reference to a temporary."); diff --git a/test/test_suite/globals/recursive_locals.c3 b/test/test_suite/globals/recursive_locals.c3 new file mode 100644 index 000000000..2cac48fa2 --- /dev/null +++ b/test/test_suite/globals/recursive_locals.c3 @@ -0,0 +1,12 @@ +struct List +{ + int x; + List* next; +} + +local const List A = { 7, &B }; +local const List B = { 8, &A }; + +extern List d; + +List c = { 7, &d };