mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Recursive references between globals are now correctly handled.
This commit is contained in:
committed by
Christoffer Lerno
parent
7fc12192f4
commit
26d25e3f74
@@ -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);
|
||||
}
|
||||
@@ -1,2 +1,3 @@
|
||||
module std:cinterop;
|
||||
|
||||
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
module bar;
|
||||
import foo local;
|
||||
|
||||
func void test()
|
||||
{
|
||||
int i = 0;
|
||||
}
|
||||
|
||||
func void main()
|
||||
{
|
||||
gonk();
|
||||
printf("Helo\n");
|
||||
}
|
||||
@@ -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 };
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
module typedefs;
|
||||
|
||||
typedef Loop as Loop2;
|
||||
typedef Loop2 as Loop3;
|
||||
typedef Loop3 as Loop;
|
||||
@@ -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
|
||||
}
|
||||
@@ -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];
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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.");
|
||||
|
||||
12
test/test_suite/globals/recursive_locals.c3
Normal file
12
test/test_suite/globals/recursive_locals.c3
Normal file
@@ -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 };
|
||||
Reference in New Issue
Block a user