mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Fixes initialization of anonymous structs. Bump version 0.2.11
This commit is contained in:
committed by
Christoffer Lerno
parent
ca21b1daac
commit
ea5d7cd2e7
@@ -208,6 +208,7 @@ LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_
|
||||
Decl *decl = const_init->type->decl;
|
||||
Decl **members = decl->strukt.members;
|
||||
uint32_t count = vec_size(members);
|
||||
if (decl->decl_kind == DECL_UNION && count) count = 1;
|
||||
LLVMValueRef *entries = NULL;
|
||||
bool was_modified = false;
|
||||
for (MemberIndex i = 0; i < count; i++)
|
||||
|
||||
@@ -3950,7 +3950,10 @@ static int decl_count_elements(Decl *structlike)
|
||||
{
|
||||
int elements = 0;
|
||||
Decl **members = structlike->strukt.members;
|
||||
VECEACH(members, i)
|
||||
unsigned member_size = vec_size(members);
|
||||
if (member_size == 0) return 0;
|
||||
if (structlike->decl_kind == DECL_UNION) member_size = 1;
|
||||
for (unsigned i = 0; i < member_size; i++)
|
||||
{
|
||||
Decl *member = members[i];
|
||||
if (member->decl_kind != DECL_VAR && !member->name)
|
||||
@@ -3972,6 +3975,12 @@ static inline void not_enough_elements(Expr *initializer, int element)
|
||||
}
|
||||
SEMA_ERROR(initializer->initializer_list[element - 1], "Too few elements in initializer, there should be elements after this one.");
|
||||
}
|
||||
|
||||
static inline bool sema_is_anon_member(Decl *decl)
|
||||
{
|
||||
return decl->decl_kind != DECL_VAR && !decl->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform analysis for a plain initializer, that is one initializing all fields.
|
||||
* @return true if analysis succeeds.
|
||||
@@ -3981,22 +3990,21 @@ static inline bool sema_expr_analyse_struct_plain_initializer(SemaContext *conte
|
||||
Expr **elements = initializer->initializer_list;
|
||||
Decl **members = assigned->strukt.members;
|
||||
MemberIndex size = (MemberIndex)vec_size(elements);
|
||||
MemberIndex expected_members = (MemberIndex)vec_size(members);
|
||||
unsigned elements_needed = decl_count_elements(assigned);
|
||||
|
||||
// 1. For struct number of members must be the same as the size of the struct.
|
||||
// Since we already handled the case with an empty initializer before going here
|
||||
// zero entries must be an error.
|
||||
assert(size > 0 && "We should already have handled the size == 0 case.");
|
||||
if (expected_members == 0)
|
||||
|
||||
// 2. We don't support this actually, but we used to. Maybe we will in the future.
|
||||
if (elements_needed == 0)
|
||||
{
|
||||
// Generate a nice error message for zero.
|
||||
SEMA_ERROR(elements[0], "Too many elements in initializer, it must be empty.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2. In case of a union, only expect a single entry.
|
||||
if (assigned->decl_kind == DECL_UNION) expected_members = 1;
|
||||
|
||||
bool failable = false;
|
||||
|
||||
bool is_bitstruct = assigned->decl_kind == DECL_BITSTRUCT;
|
||||
@@ -4008,17 +4016,18 @@ static inline bool sema_expr_analyse_struct_plain_initializer(SemaContext *conte
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Loop through all elements.
|
||||
MemberIndex max_loop = MAX(size, expected_members);
|
||||
MemberIndex max_loop = size > elements_needed ? size : elements_needed;
|
||||
for (MemberIndex i = 0; i < max_loop; i++)
|
||||
{
|
||||
// 4. Check if we exceeded the list of elements in the struct/union.
|
||||
// This way we can check the other elements which might help the
|
||||
// user pinpoint where they put the double elements.
|
||||
if (i >= expected_members)
|
||||
if (i >= elements_needed)
|
||||
{
|
||||
assert(i < size);
|
||||
SEMA_ERROR(elements[i], "Too many elements in initializer, expected only %d.", expected_members);
|
||||
SEMA_ERROR(elements[i], "Too many elements in initializer, expected only %d.", elements_needed);
|
||||
return false;
|
||||
}
|
||||
// 5. We might have anonymous members
|
||||
@@ -4048,14 +4057,15 @@ static inline bool sema_expr_analyse_struct_plain_initializer(SemaContext *conte
|
||||
return false;
|
||||
}
|
||||
Expr *new_initializer = expr_new(EXPR_INITIALIZER_LIST, elements[i]->span);
|
||||
int max_index_to_copy = MIN(i + sub_element_count, size);
|
||||
int max_index_to_copy = i + sub_element_count < size ? i + sub_element_count : size;
|
||||
for (int j = i; j < max_index_to_copy; j++)
|
||||
{
|
||||
vec_add(new_initializer->initializer_list, elements[j]);
|
||||
}
|
||||
int reduce_by = max_index_to_copy - i - 1;
|
||||
size -= reduce_by;
|
||||
max_loop = MAX(size, expected_members);
|
||||
elements_needed -= reduce_by;
|
||||
max_loop = MAX(size, elements_needed);
|
||||
assert(size <= vec_size(initializer->initializer_list));
|
||||
vec_resize(initializer->initializer_list, (unsigned)size);
|
||||
elements = initializer->initializer_list;
|
||||
@@ -4064,6 +4074,7 @@ static inline bool sema_expr_analyse_struct_plain_initializer(SemaContext *conte
|
||||
if (i >= size)
|
||||
{
|
||||
not_enough_elements(initializer, i);
|
||||
return false;
|
||||
}
|
||||
Expr *element = elements[i];
|
||||
// 6. We know the required type, so resolve the expression.
|
||||
@@ -4078,7 +4089,7 @@ static inline bool sema_expr_analyse_struct_plain_initializer(SemaContext *conte
|
||||
if (failable) initializer->type = type_get_failable(initializer->type);
|
||||
|
||||
// 6. There's the case of too few values as well. Mark the last field as wrong.
|
||||
assert(expected_members <= size);
|
||||
assert(elements_needed <= size);
|
||||
|
||||
if (expr_is_constant_eval(initializer, CONSTANT_EVAL_ANY))
|
||||
{
|
||||
@@ -4225,6 +4236,7 @@ static inline bool sema_expr_analyse_initializer(SemaContext *context, Type *ext
|
||||
// EXPR_DESIGNATED_INITIALIZER_LIST
|
||||
// or EXPR_INITIALIZER_LIST
|
||||
|
||||
// 1. Designated initializer is separately evaluated.
|
||||
if (expr->expr_kind == EXPR_DESIGNATED_INITIALIZER_LIST)
|
||||
{
|
||||
expr->type = external_type;
|
||||
@@ -4233,13 +4245,17 @@ static inline bool sema_expr_analyse_initializer(SemaContext *context, Type *ext
|
||||
|
||||
assert(expr->expr_kind == EXPR_INITIALIZER_LIST);
|
||||
|
||||
// 2. Grab the expressions inside.
|
||||
Expr **init_expressions = expr->initializer_list;
|
||||
|
||||
unsigned init_expression_count = vec_size(init_expressions);
|
||||
|
||||
// 1. Zero size init will initialize to empty.
|
||||
// 3. Zero size init will initialize to empty.
|
||||
if (init_expression_count == 0)
|
||||
{
|
||||
if (external_type->type_kind == TYPE_INFERRED_ARRAY)
|
||||
{
|
||||
REMINDER("Handle zero size inferred array.");
|
||||
}
|
||||
external_type = sema_type_lower_by_size(external_type, 0);
|
||||
expr->type = external_type;
|
||||
ConstInitializer *initializer = CALLOCS(ConstInitializer);
|
||||
@@ -4249,15 +4265,19 @@ static inline bool sema_expr_analyse_initializer(SemaContext *context, Type *ext
|
||||
return true;
|
||||
}
|
||||
|
||||
// 4. If we have an inferred array, we need to set the size.
|
||||
external_type = sema_type_lower_by_size(external_type, init_expression_count);
|
||||
assigned = sema_type_lower_by_size(assigned, init_expression_count);
|
||||
|
||||
// 5. Set the type.
|
||||
expr->type = external_type;
|
||||
|
||||
// 6. We might have a complist, because were analyzing $foo = { ... } or similar.
|
||||
if (external_type == type_complist)
|
||||
{
|
||||
return sema_expr_analyse_untyped_initializer(context, expr);
|
||||
}
|
||||
// 3. Otherwise use the plain initializer.
|
||||
// 7. If not, then we see if we have an array.
|
||||
if (assigned->type_kind == TYPE_UNTYPED_LIST ||
|
||||
assigned->type_kind == TYPE_ARRAY ||
|
||||
assigned->type_kind == TYPE_INFERRED_ARRAY ||
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define COMPILER_VERSION "0.2.10"
|
||||
#define COMPILER_VERSION "0.2.11"
|
||||
86
test/test_suite/struct/nested_struct_init.c3t
Normal file
86
test/test_suite/struct/nested_struct_init.c3t
Normal file
@@ -0,0 +1,86 @@
|
||||
// #target: macos-x64
|
||||
module foo;
|
||||
import libc;
|
||||
|
||||
struct Matrix2x2
|
||||
{
|
||||
union
|
||||
{
|
||||
struct {
|
||||
float m00, m01, m10, m11;
|
||||
}
|
||||
float[4] m;
|
||||
}
|
||||
}
|
||||
|
||||
struct Matrix2x2_b
|
||||
{
|
||||
union
|
||||
{
|
||||
float[4] m;
|
||||
struct {
|
||||
float m00, m01, m10, m11;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn void main()
|
||||
{
|
||||
Matrix2x2 m = { 1, 2, 3, 4 };
|
||||
Matrix2x2_b m2 = { { 1, 2, 3, 4 } };
|
||||
libc::printf("%f %f %f %f\n", m.m00, m.m[1], m.m10, m.m[3]);
|
||||
}
|
||||
/* #expect: foo.ll
|
||||
|
||||
%Matrix2x2 = type { %anon }
|
||||
%anon = type { %anon.0 }
|
||||
%anon.0 = type { float, float, float, float }
|
||||
%Matrix2x2_b = type { %anon.1 }
|
||||
%anon.1 = type { [4 x float] }
|
||||
@.typeid.foo.anon = linkonce constant { i8, i64 } { i8 10, i64 4 }, align 8
|
||||
@.typeid.foo.anon.1 = linkonce constant { i8, i64 } { i8 11, i64 2 }, align 8
|
||||
@.typeid.foo.Matrix2x2 = linkonce constant { i8, i64 } { i8 10, i64 1 }, align 8
|
||||
@.typeid.foo.anon.2 = linkonce constant { i8, i64 } { i8 10, i64 4 }, align 8
|
||||
@.typeid.foo.anon.3 = linkonce constant { i8, i64 } { i8 11, i64 2 }, align 8
|
||||
@.typeid.foo.Matrix2x2_b = linkonce constant { i8, i64 } { i8 10, i64 1 }, align 8
|
||||
@.__const = private unnamed_addr constant %Matrix2x2 { %anon { %anon.0 { float 1.000000e+00, float 2.000000e+00, float 3.000000e+00, float 4.000000e+00 } } }, align 4
|
||||
@.__const.4 = private unnamed_addr constant %Matrix2x2_b { %anon.1 { [4 x float] [float 1.000000e+00, float 2.000000e+00, float 3.000000e+00, float 4.000000e+00] } }, align 4
|
||||
@.str = private unnamed_addr constant [13 x i8] c"%f %f %f %f\0A\00", align 1
|
||||
; Function Attrs: nounwind
|
||||
define void @foo.main() #0 {
|
||||
entry:
|
||||
%m = alloca %Matrix2x2, align 4
|
||||
%m2 = alloca %Matrix2x2_b, align 4
|
||||
%0 = bitcast %Matrix2x2* %m to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %0, i8* align 4 bitcast (%Matrix2x2* @.__const to i8*), i32 16, i1 false)
|
||||
%1 = bitcast %Matrix2x2_b* %m2 to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %1, i8* align 4 bitcast (%Matrix2x2_b* @.__const.4 to i8*), i32 16, i1 false)
|
||||
%2 = getelementptr inbounds %Matrix2x2, %Matrix2x2* %m, i32 0, i32 0
|
||||
%3 = bitcast %anon* %2 to %anon.0*
|
||||
%4 = getelementptr inbounds %anon.0, %anon.0* %3, i32 0, i32 0
|
||||
%5 = load float, float* %4, align 4
|
||||
%fpfpext = fpext float %5 to double
|
||||
%6 = getelementptr inbounds %Matrix2x2, %Matrix2x2* %m, i32 0, i32 0
|
||||
%7 = bitcast %anon* %6 to [4 x float]*
|
||||
%8 = getelementptr inbounds [4 x float], [4 x float]* %7, i64 0, i64 1
|
||||
%9 = load float, float* %8, align 4
|
||||
%fpfpext1 = fpext float %9 to double
|
||||
%10 = getelementptr inbounds %Matrix2x2, %Matrix2x2* %m, i32 0, i32 0
|
||||
%11 = bitcast %anon* %10 to %anon.0*
|
||||
%12 = getelementptr inbounds %anon.0, %anon.0* %11, i32 0, i32 2
|
||||
%13 = load float, float* %12, align 4
|
||||
%fpfpext2 = fpext float %13 to double
|
||||
%14 = getelementptr inbounds %Matrix2x2, %Matrix2x2* %m, i32 0, i32 0
|
||||
%15 = bitcast %anon* %14 to [4 x float]*
|
||||
%16 = getelementptr inbounds [4 x float], [4 x float]* %15, i64 0, i64 3
|
||||
%17 = load float, float* %16, align 4
|
||||
%fpfpext3 = fpext float %17 to double
|
||||
%18 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str, i32 0, i32 0), double %fpfpext, double %fpfpext1, double %fpfpext2, double %fpfpext3)
|
||||
ret void
|
||||
}
|
||||
; Function Attrs: nounwind
|
||||
define i32 @main(i32 %0, i8** %1) #0 {
|
||||
entry:
|
||||
call void @foo.main()
|
||||
ret i32 0
|
||||
}
|
||||
74
test/test_suite2/struct/nested_struct_init.c3t
Normal file
74
test/test_suite2/struct/nested_struct_init.c3t
Normal file
@@ -0,0 +1,74 @@
|
||||
// #target: macos-x64
|
||||
module foo;
|
||||
import libc;
|
||||
|
||||
struct Matrix2x2
|
||||
{
|
||||
union
|
||||
{
|
||||
struct {
|
||||
float m00, m01, m10, m11;
|
||||
}
|
||||
float[4] m;
|
||||
}
|
||||
}
|
||||
|
||||
struct Matrix2x2_b
|
||||
{
|
||||
union
|
||||
{
|
||||
float[4] m;
|
||||
struct {
|
||||
float m00, m01, m10, m11;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn void main()
|
||||
{
|
||||
Matrix2x2 m = { 1, 2, 3, 4 };
|
||||
Matrix2x2_b m2 = { { 1, 2, 3, 4 } };
|
||||
libc::printf("%f %f %f %f\n", m.m00, m.m[1], m.m10, m.m[3]);
|
||||
}
|
||||
/* #expect: foo.ll
|
||||
|
||||
%Matrix2x2 = type { %anon }
|
||||
%anon = type { %anon.0 }
|
||||
%anon.0 = type { float, float, float, float }
|
||||
%Matrix2x2_b = type { %anon.1 }
|
||||
%anon.1 = type { [4 x float] }
|
||||
@.typeid.foo.anon = linkonce constant { i8, i64 } { i8 10, i64 4 }, align 8
|
||||
@.typeid.foo.anon.1 = linkonce constant { i8, i64 } { i8 11, i64 2 }, align 8
|
||||
@.typeid.foo.Matrix2x2 = linkonce constant { i8, i64 } { i8 10, i64 1 }, align 8
|
||||
@.typeid.foo.anon.2 = linkonce constant { i8, i64 } { i8 10, i64 4 }, align 8
|
||||
@.typeid.foo.anon.3 = linkonce constant { i8, i64 } { i8 11, i64 2 }, align 8
|
||||
@.typeid.foo.Matrix2x2_b = linkonce constant { i8, i64 } { i8 10, i64 1 }, align 8
|
||||
@.__const = private unnamed_addr constant %Matrix2x2 { %anon { %anon.0 { float 1.000000e+00, float 2.000000e+00, float 3.000000e+00, float 4.000000e+00 } } }, align 4
|
||||
@.__const.4 = private unnamed_addr constant %Matrix2x2_b { %anon.1 { [4 x float] [float 1.000000e+00, float 2.000000e+00, float 3.000000e+00, float 4.000000e+00] } }, align 4
|
||||
@.str = private unnamed_addr constant [13 x i8] c"%f %f %f %f\0A\00", align 1
|
||||
; Function Attrs: nounwind
|
||||
define void @foo.main() #0 {
|
||||
entry:
|
||||
%m = alloca %Matrix2x2, align 4
|
||||
%m2 = alloca %Matrix2x2_b, align 4
|
||||
call void @llvm.memcpy.p0.p0.i32(ptr align 4 %m, ptr align 4 @.__const, i32 16, i1 false)
|
||||
call void @llvm.memcpy.p0.p0.i32(ptr align 4 %m2, ptr align 4 @.__const.4, i32 16, i1 false)
|
||||
%0 = getelementptr inbounds %Matrix2x2, ptr %m, i32 0, i32 0
|
||||
%1 = getelementptr inbounds %anon.0, ptr %0, i32 0, i32 0
|
||||
%2 = load float, ptr %1, align 4
|
||||
%fpfpext = fpext float %2 to double
|
||||
%3 = getelementptr inbounds %Matrix2x2, ptr %m, i32 0, i32 0
|
||||
%4 = getelementptr inbounds [4 x float], ptr %3, i64 0, i64 1
|
||||
%5 = load float, ptr %4, align 4
|
||||
%fpfpext1 = fpext float %5 to double
|
||||
%6 = getelementptr inbounds %Matrix2x2, ptr %m, i32 0, i32 0
|
||||
%7 = getelementptr inbounds %anon.0, ptr %6, i32 0, i32 2
|
||||
%8 = load float, ptr %7, align 4
|
||||
%fpfpext2 = fpext float %8 to double
|
||||
%9 = getelementptr inbounds %Matrix2x2, ptr %m, i32 0, i32 0
|
||||
%10 = getelementptr inbounds [4 x float], ptr %9, i64 0, i64 3
|
||||
%11 = load float, ptr %10, align 4
|
||||
%fpfpext3 = fpext float %11 to double
|
||||
%12 = call i32 (ptr, ...) @printf(ptr @.str, double %fpfpext, double %fpfpext1, double %fpfpext2, double %fpfpext3)
|
||||
ret void
|
||||
}
|
||||
Reference in New Issue
Block a user