mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Work on unions and anonymous structs/unions.
This commit is contained in:
11
missing.txt
11
missing.txt
@@ -1,14 +1,15 @@
|
||||
Things missing:
|
||||
|
||||
* Attributes
|
||||
- All types: @noreflect
|
||||
- All types: @noreflect, @deprecated
|
||||
- Struct: @packed, @aligned, @opaque
|
||||
- Enums: @distinct, @noreflect
|
||||
- Unions: @packed, @aligned, @opaque
|
||||
- Functions: @inline, @reflect, @noreturn, @section, @unused, @used, @interrupt, @naked, @convention()
|
||||
- Calls: @noinline
|
||||
- Calls: @noinline, @inline
|
||||
- Variables, parameters: @unused
|
||||
- Constants, globals: @unused, @used, @section
|
||||
- Labels: @unused
|
||||
|
||||
* Designated initializer
|
||||
- Array initializer
|
||||
@@ -17,6 +18,7 @@ Things missing:
|
||||
* Initializers
|
||||
- Array initializers
|
||||
- Union initializers
|
||||
- Initializers with anonymous members
|
||||
|
||||
* Asserts
|
||||
- assert, $assert
|
||||
@@ -36,7 +38,10 @@ Things missing:
|
||||
- Bitstruct
|
||||
- Enumset
|
||||
- Typeid
|
||||
- Union usage
|
||||
|
||||
* Struct / union
|
||||
- Cast to union?
|
||||
- Structural typed anonymous structs and casts to them.
|
||||
|
||||
* Expressions
|
||||
- Disallow x >= 0 and x < 0 on unsigned types unless in a macro.
|
||||
|
||||
@@ -106,24 +106,67 @@ struct TestStruct2
|
||||
}
|
||||
|
||||
union TestUnion
|
||||
{
|
||||
int a;
|
||||
double f;
|
||||
TestStruct2 e;
|
||||
}
|
||||
union SimpleUnion
|
||||
{
|
||||
int a;
|
||||
double f;
|
||||
}
|
||||
|
||||
|
||||
func TestStruct structTest(int i)
|
||||
struct AnonStruct
|
||||
{
|
||||
int a;
|
||||
struct sune
|
||||
{
|
||||
int b;
|
||||
int c;
|
||||
}
|
||||
struct
|
||||
{
|
||||
int b1;
|
||||
int c1;
|
||||
}
|
||||
union
|
||||
{
|
||||
int b2;
|
||||
int c2;
|
||||
}
|
||||
int x;
|
||||
}
|
||||
|
||||
TestUnion tu;
|
||||
/* TestStruct foo = { i };
|
||||
TestStruct foo2 = { a = i };*/
|
||||
func void testAnonStruct()
|
||||
{
|
||||
AnonStruct s = { b2 = 3, b1 = 7, sune.b = 1 };
|
||||
s.sune.b = 1;
|
||||
s.b1 = 2;
|
||||
s.b2 = 3;
|
||||
s.c2 = 4;
|
||||
|
||||
}
|
||||
|
||||
func void testUnion()
|
||||
{
|
||||
SimpleUnion s;
|
||||
s.a = 1;
|
||||
s.f = 1.0;
|
||||
//s = { f = 1.0 };
|
||||
TestUnion tu = { e = TestStruct2 { c = 1 } };
|
||||
tu.e = TestStruct2 { c = 1 };
|
||||
}
|
||||
|
||||
func TestStruct2 structTest(int i)
|
||||
{
|
||||
TestStruct foo = { i };
|
||||
TestStruct foo2 = { a = i };
|
||||
TestStruct foo3 = TestStruct { i };
|
||||
return foo3;
|
||||
/* TestStruct2 bar = { c = 2 };
|
||||
TestStruct2 bar = { c = 2 };
|
||||
int x = 3 * i;
|
||||
TestStruct2 bar2 = { b.a = x, a.a = x + 1 };
|
||||
return bar2;*/
|
||||
return bar2;
|
||||
}
|
||||
func void enumInferenceTest()
|
||||
{
|
||||
|
||||
@@ -8,7 +8,6 @@ static void fprint_asts_recursive(FILE *file, Ast **asts, int indent);
|
||||
|
||||
Decl *decl_new(DeclKind decl_kind, Token name, Visibility visibility)
|
||||
{
|
||||
assert(name.string);
|
||||
Decl *decl = CALLOCS(Decl);
|
||||
decl->decl_kind = decl_kind;
|
||||
decl->name_span = name.span;
|
||||
|
||||
@@ -227,6 +227,7 @@ typedef struct
|
||||
typedef struct
|
||||
{
|
||||
uint32_t abi_alignment;
|
||||
uint32_t id;
|
||||
uint64_t size;
|
||||
Decl **members;
|
||||
} StructDecl;
|
||||
@@ -237,7 +238,11 @@ typedef struct _VarDecl
|
||||
unsigned id : 16;
|
||||
VarDeclKind kind : 3;
|
||||
TypeInfo *type_info;
|
||||
Expr *init_expr;
|
||||
union
|
||||
{
|
||||
Expr *init_expr;
|
||||
Decl *parent;
|
||||
};
|
||||
void *backend_ref;
|
||||
void *backend_debug_ref;
|
||||
} VarDecl;
|
||||
@@ -364,7 +369,11 @@ typedef struct _Decl
|
||||
{
|
||||
struct
|
||||
{
|
||||
Decl** method_functions;
|
||||
union
|
||||
{
|
||||
Decl* parent_struct;
|
||||
Decl** method_functions;
|
||||
};
|
||||
union
|
||||
{
|
||||
ErrorDecl error;
|
||||
@@ -460,8 +469,6 @@ typedef struct
|
||||
Token sub_element;
|
||||
Decl *ref;
|
||||
};
|
||||
// TODO cleanup
|
||||
int index;
|
||||
} ExprAccess;
|
||||
|
||||
typedef struct
|
||||
@@ -997,7 +1004,6 @@ bool cast_to_runtime(Expr *expr);
|
||||
void cast_to_smallest_runtime(Expr *expr);
|
||||
|
||||
void llvm_codegen(Context *context);
|
||||
void llvm_set_struct_size_alignment(Decl *decl);
|
||||
|
||||
|
||||
bool sema_analyse_expr_of_required_type(Context *context, Type *to, Expr *expr);
|
||||
@@ -1182,6 +1188,20 @@ static inline Type *type_reduced(Type *type)
|
||||
return canonical;
|
||||
}
|
||||
|
||||
static inline bool type_is_structlike(Type *type)
|
||||
{
|
||||
assert(type->canonical = type);
|
||||
switch (type->type_kind)
|
||||
{
|
||||
case TYPE_UNION:
|
||||
case TYPE_STRUCT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static inline Type *type_reduced_from_expr(Expr *expr)
|
||||
{
|
||||
return type_reduced(expr->type);
|
||||
|
||||
@@ -54,10 +54,38 @@ static inline LLVMValueRef gencontext_emit_subscript_addr(GenContext *context, E
|
||||
}
|
||||
}
|
||||
|
||||
static LLVMValueRef gencontext_emit_member_addr(GenContext *context, LLVMValueRef value, Decl *parent, Decl *member)
|
||||
{
|
||||
unsigned index;
|
||||
Decl *current_parent;
|
||||
if (decl_is_struct_type(member))
|
||||
{
|
||||
index = member->strukt.id;
|
||||
current_parent = member->parent_struct;
|
||||
}
|
||||
else
|
||||
{
|
||||
index = member->var.id;
|
||||
current_parent = member->var.parent;
|
||||
}
|
||||
assert(current_parent);
|
||||
if (parent != current_parent)
|
||||
{
|
||||
value = gencontext_emit_member_addr(context, value, parent, current_parent);
|
||||
}
|
||||
|
||||
if (current_parent->decl_kind == DECL_UNION)
|
||||
{
|
||||
return LLVMBuildBitCast(context->builder, value, LLVMPointerType(llvm_type(member->type), 0), "");
|
||||
}
|
||||
return LLVMBuildStructGEP2(context->builder, llvm_type(current_parent->type), value, index, "");
|
||||
}
|
||||
static inline LLVMValueRef gencontext_emit_access_addr(GenContext *context, Expr *expr)
|
||||
{
|
||||
LLVMValueRef value = gencontext_emit_address(context, expr->access_expr.parent);
|
||||
return LLVMBuildStructGEP2(context->builder, llvm_type(expr->access_expr.parent->type), value, (unsigned)expr->access_expr.index, "");
|
||||
Expr *parent = expr->access_expr.parent;
|
||||
LLVMValueRef value = gencontext_emit_address(context, parent);
|
||||
Decl *member = expr->access_expr.ref;
|
||||
return gencontext_emit_member_addr(context, value, parent->type->canonical->decl, member);
|
||||
}
|
||||
|
||||
LLVMValueRef gencontext_emit_scoped_expr(GenContext *context, Expr *expr)
|
||||
@@ -177,6 +205,70 @@ static inline LLVMValueRef gencontext_emit_cast_expr(GenContext *context, Expr *
|
||||
return gencontext_emit_cast(context, expr->cast_expr.kind, rhs, expr->type->canonical, expr->cast_expr.expr->type->canonical);
|
||||
}
|
||||
|
||||
static inline LLVMValueRef gencontext_emit_initializer_list_expr(GenContext *context, Expr *expr)
|
||||
{
|
||||
LLVMTypeRef type = llvm_type(expr->type);
|
||||
LLVMValueRef ref = gencontext_emit_alloca(context, type, "literal");
|
||||
|
||||
if (expr->expr_initializer.init_type == INITIALIZER_ZERO)
|
||||
{
|
||||
LLVMBuildMemSet(context->builder,
|
||||
ref,
|
||||
LLVMConstInt(llvm_type(type_byte), 0, false),
|
||||
LLVMConstInt(llvm_type(type_ulong), expr->type->decl->strukt.size, false),
|
||||
expr->type->decl->strukt.abi_alignment);
|
||||
return ref;
|
||||
}
|
||||
|
||||
Expr **elements = expr->expr_initializer.initializer_expr;
|
||||
|
||||
bool is_union = expr->type->canonical->type_kind == TYPE_UNION;
|
||||
if (expr->expr_initializer.init_type == INITIALIZER_NORMAL)
|
||||
{
|
||||
assert(!is_union);
|
||||
VECEACH(elements, i)
|
||||
{
|
||||
Expr *element = elements[i];
|
||||
LLVMValueRef init_value = gencontext_emit_expr(context, element);
|
||||
LLVMValueRef subref = LLVMBuildStructGEP2(context->builder, type, ref, i, "");
|
||||
LLVMBuildStore(context->builder, init_value, subref);
|
||||
}
|
||||
return ref;
|
||||
}
|
||||
|
||||
|
||||
// Clear the temp.
|
||||
LLVMBuildMemSet(context->builder, ref, LLVMConstInt(llvm_type(type_byte), 0, false),
|
||||
LLVMConstInt(llvm_type(type_ulong), expr->type->decl->strukt.size, false), expr->type->decl->strukt.abi_alignment);
|
||||
|
||||
|
||||
VECEACH(elements, i)
|
||||
{
|
||||
Expr *element = elements[i];
|
||||
LLVMValueRef sub_value = gencontext_emit_expr(context, element->designated_init_expr.value);
|
||||
Decl *parent = expr->type->decl;
|
||||
DesignatedInitPath *path = &element->designated_init_expr.path;
|
||||
LLVMValueRef subref = ref;
|
||||
assert(element->expr_kind == EXPR_DESIGNATED_INIT);
|
||||
// If this is a union, we down a step to begin with.
|
||||
if (is_union)
|
||||
{
|
||||
subref = LLVMBuildBitCast(context->builder, ref, LLVMPointerType(llvm_type(path->decl->type), 0), "unioncast");
|
||||
parent = path->decl;
|
||||
path = path->sub_path;
|
||||
}
|
||||
while (path)
|
||||
{
|
||||
subref = LLVMBuildStructGEP2(context->builder, llvm_type(parent->type), subref, path->decl->var.id, "access");
|
||||
parent = path->decl;
|
||||
path = path->sub_path;
|
||||
}
|
||||
LLVMBuildStore(context->builder, sub_value, subref);
|
||||
}
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
static inline LLVMValueRef gencontext_emit_inc_dec_change(GenContext *context, bool use_mod, LLVMValueRef current_value, Expr *expr, int diff)
|
||||
{
|
||||
Type *type = type_reduced_from_expr(expr);
|
||||
@@ -580,10 +672,6 @@ static LLVMValueRef gencontext_emit_binary_expr(GenContext *context, Expr *expr)
|
||||
if (binary_op == BINARYOP_ASSIGN)
|
||||
{
|
||||
LLVMValueRef addr = gencontext_emit_address(context, expr->binary_expr.left);
|
||||
if (expr->binary_expr.right->expr_kind == EXPR_INITIALIZER_LIST)
|
||||
{
|
||||
return gencontext_emit_initialization_from_expr(context, addr, expr->binary_expr.right);
|
||||
}
|
||||
LLVMValueRef value = gencontext_emit_expr(context, expr->binary_expr.right);
|
||||
LLVMBuildStore(context->builder, value, addr);
|
||||
return value;
|
||||
@@ -725,7 +813,7 @@ static inline LLVMValueRef gencontext_emit_access_expr(GenContext *context, Expr
|
||||
{
|
||||
// Improve, add string description to the access?
|
||||
LLVMValueRef value = gencontext_emit_address(context, expr->access_expr.parent);
|
||||
LLVMValueRef val = LLVMBuildStructGEP2(context->builder, llvm_type(expr->access_expr.parent->type), value, (unsigned)expr->access_expr.index, "");
|
||||
LLVMValueRef val = LLVMBuildStructGEP2(context->builder, llvm_type(expr->access_expr.parent->type), value, expr->access_expr.ref->var.id, "");
|
||||
return LLVMBuildLoad2(context->builder, gencontext_get_llvm_type(context, expr->type), val, "");
|
||||
}
|
||||
|
||||
@@ -741,54 +829,6 @@ static inline LLVMValueRef gencontext_emit_expression_list_expr(GenContext *cont
|
||||
|
||||
|
||||
|
||||
static inline LLVMValueRef gencontext_emit_initializer_list_expr(GenContext *context, Expr *expr)
|
||||
{
|
||||
LLVMTypeRef type = llvm_type(expr->type);
|
||||
LLVMValueRef value = LLVMGetUndef(type);
|
||||
|
||||
if (expr->expr_initializer.init_type == INITIALIZER_ZERO)
|
||||
{
|
||||
LLVMValueRef ref = gencontext_emit_alloca(context, type, "temp");
|
||||
value = LLVMBuildMemSet(context->builder, ref, LLVMConstInt(llvm_type(type_byte), 0, false),
|
||||
LLVMConstInt(llvm_type(type_ulong), expr->type->decl->strukt.size, false), expr->type->decl->strukt.abi_alignment);
|
||||
return value;
|
||||
}
|
||||
|
||||
Expr **elements = expr->expr_initializer.initializer_expr;
|
||||
|
||||
if (expr->expr_initializer.init_type == INITIALIZER_NORMAL)
|
||||
{
|
||||
VECEACH(elements, i)
|
||||
{
|
||||
LLVMValueRef init_value = gencontext_emit_expr(context, elements[i]);
|
||||
value = LLVMBuildInsertValue(context->builder, value, init_value, i, "literal");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
LLVMValueRef ref = gencontext_emit_alloca(context, type, "temp");
|
||||
value = LLVMBuildMemSet(context->builder, ref, LLVMConstInt(llvm_type(type_byte), 0, false),
|
||||
LLVMConstInt(llvm_type(type_ulong), expr->type->decl->strukt.size, false), expr->type->decl->strukt.abi_alignment);
|
||||
|
||||
VECEACH(elements, i)
|
||||
{
|
||||
Expr *element = elements[i];
|
||||
LLVMValueRef sub_value = gencontext_emit_expr(context, element->designated_init_expr.value);
|
||||
Decl *parent = expr->type->decl;
|
||||
DesignatedInitPath *path = &element->designated_init_expr.path;
|
||||
LLVMValueRef subref = ref;
|
||||
assert(element->expr_kind == EXPR_DESIGNATED_INIT);
|
||||
while (path)
|
||||
{
|
||||
subref = LLVMBuildStructGEP2(context->builder, llvm_type(parent->type), subref, path->decl->var.id, "access");
|
||||
parent = path->decl;
|
||||
path = path->sub_path;
|
||||
}
|
||||
LLVMBuildStore(context->builder, sub_value, subref);
|
||||
}
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
static inline LLVMValueRef gencontext_emit_expr_block(GenContext *context, Expr *expr)
|
||||
{
|
||||
|
||||
@@ -52,20 +52,28 @@ static inline LLVMTypeRef llvm_type_from_decl(LLVMContextRef context, Decl *decl
|
||||
}
|
||||
case DECL_UNION:
|
||||
{
|
||||
LLVMTypeRef max_type = NULL;
|
||||
Decl *max_type = NULL;
|
||||
unsigned long long max_size = 0;
|
||||
VECEACH(decl->strukt.members, i)
|
||||
{
|
||||
LLVMTypeRef type = llvm_get_type(context, decl->strukt.members[i]->type);
|
||||
unsigned long long size = LLVMStoreSizeOfType(target_data_layout(), type);
|
||||
Decl *member = decl->strukt.members[i];
|
||||
unsigned size = type_size(member->type);
|
||||
if (size > max_size || !max_type)
|
||||
{
|
||||
max_size = size;
|
||||
max_type = type;
|
||||
max_type = member;
|
||||
}
|
||||
}
|
||||
LLVMTypeRef type = LLVMStructCreateNamed(context, decl->external_name);
|
||||
LLVMStructSetBody(type, &max_type, 1, false);
|
||||
if (max_type)
|
||||
{
|
||||
LLVMTypeRef type_ref = llvm_get_type(context, max_type->type);
|
||||
LLVMStructSetBody(type, &type_ref, 1, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
LLVMStructSetBody(type, NULL, 0, true);
|
||||
}
|
||||
return type;
|
||||
}
|
||||
case DECL_ENUM:
|
||||
@@ -222,9 +230,3 @@ LLVMTypeRef gencontext_get_llvm_type(GenContext *context, Type *type)
|
||||
return llvm_get_type(context->context, type);
|
||||
}
|
||||
|
||||
void llvm_set_struct_size_alignment(Decl *decl)
|
||||
{
|
||||
LLVMTypeRef type = llvm_get_type(LLVMGetGlobalContext(), decl->type);
|
||||
decl->strukt.size = LLVMStoreSizeOfType(target_data_layout(), type);
|
||||
decl->strukt.abi_alignment = LLVMPreferredAlignmentOfType(target_data_layout(), type);
|
||||
}
|
||||
|
||||
@@ -989,11 +989,11 @@ bool parse_struct_body(Context *context, Decl *parent, Decl *visible_parent)
|
||||
Decl *member;
|
||||
if (context->next_tok.type != TOKEN_IDENT)
|
||||
{
|
||||
Token name_replacement = context->tok;
|
||||
name_replacement.string = NULL;
|
||||
member = decl_new_with_type(name_replacement, decl_kind, parent->visibility);
|
||||
advance(context);
|
||||
}
|
||||
Token name_replacement = context->tok;
|
||||
name_replacement.string = NULL;
|
||||
member = decl_new_with_type(name_replacement, decl_kind, parent->visibility);
|
||||
advance(context);
|
||||
}
|
||||
else
|
||||
{
|
||||
advance(context);
|
||||
@@ -1010,6 +1010,8 @@ bool parse_struct_body(Context *context, Decl *parent, Decl *visible_parent)
|
||||
advance_and_verify(context, TOKEN_IDENT);
|
||||
}
|
||||
if (!parse_attributes(context, member)) return false;
|
||||
member->parent_struct = parent;
|
||||
member->strukt.id = vec_size(parent->strukt.members);
|
||||
parent->strukt.members = VECADD(parent->strukt.members, member);
|
||||
if (!parse_struct_body(context, member, context->tok.type == TOKEN_IDENT ? member : visible_parent))
|
||||
{
|
||||
@@ -1036,6 +1038,7 @@ bool parse_struct_body(Context *context, Decl *parent, Decl *visible_parent)
|
||||
unsigned index = vec_size(parent->strukt.members);
|
||||
parent->strukt.members = VECADD(parent->strukt.members, member);
|
||||
member->var.id = index;
|
||||
member->var.parent = parent;
|
||||
advance(context);
|
||||
if (context->tok.type != TOKEN_COMMA) break;
|
||||
}
|
||||
|
||||
@@ -38,6 +38,53 @@ static inline bool sema_analyse_error(Context *context __unused, Decl *decl)
|
||||
}
|
||||
|
||||
|
||||
static inline void sema_set_struct_size(Decl *decl)
|
||||
{
|
||||
// TODO packed
|
||||
uint64_t size = 0;
|
||||
uint64_t alignment = 0;
|
||||
VECEACH(decl->strukt.members, i)
|
||||
{
|
||||
Decl *member = decl->strukt.members[i];
|
||||
Type *canonical = member->type->canonical;
|
||||
uint64_t member_size = type_size(canonical);
|
||||
uint64_t member_alignment = type_abi_alignment(canonical);
|
||||
assert(member_size > 0);
|
||||
// Add padding.
|
||||
if (member_alignment && (size % member_alignment))
|
||||
{
|
||||
size += member_alignment - size % member_alignment;
|
||||
}
|
||||
// Add size.
|
||||
size += member_size;
|
||||
if (member_alignment > alignment) alignment = member_alignment;
|
||||
}
|
||||
decl->strukt.abi_alignment = alignment;
|
||||
if (alignment && size % alignment)
|
||||
{
|
||||
size += alignment - size % alignment;
|
||||
}
|
||||
decl->strukt.size = size;
|
||||
}
|
||||
|
||||
static inline void sema_set_union_size(Decl *decl)
|
||||
{
|
||||
uint64_t size = 0;
|
||||
uint64_t alignment = 0;
|
||||
VECEACH(decl->strukt.members, i)
|
||||
{
|
||||
Decl *member = decl->strukt.members[i];
|
||||
Type *canonical = member->type->canonical;
|
||||
uint64_t member_size = type_size(canonical);
|
||||
uint64_t member_alignment = type_abi_alignment(canonical);
|
||||
if (member_size > size) size = member_size;
|
||||
if (member_alignment > alignment) alignment = member_alignment;
|
||||
}
|
||||
decl->strukt.abi_alignment = alignment;
|
||||
decl->strukt.size = size;
|
||||
}
|
||||
|
||||
|
||||
static inline bool sema_analyse_struct_member(Context *context, Decl *decl)
|
||||
{
|
||||
assert(decl->resolve_status == RESOLVE_NOT_DONE);
|
||||
@@ -63,12 +110,19 @@ static inline bool sema_analyse_struct_member(Context *context, Decl *decl)
|
||||
decl_poison(decl);
|
||||
}
|
||||
}
|
||||
if (decl->decl_kind == DECL_UNION)
|
||||
{
|
||||
sema_set_union_size(decl);
|
||||
}
|
||||
else
|
||||
{
|
||||
sema_set_struct_size(decl);
|
||||
}
|
||||
DEBUG_LOG("Analysis complete.");
|
||||
return decl_ok(decl);
|
||||
}
|
||||
assert(decl->decl_kind == DECL_VAR);
|
||||
assert(decl->var.kind == VARDECL_MEMBER);
|
||||
assert(!decl->var.init_expr);
|
||||
if (!sema_resolve_type_info(context, decl->var.type_info))
|
||||
{
|
||||
decl_poison(decl);
|
||||
@@ -92,7 +146,7 @@ static inline bool sema_analyse_struct_union(Context *context, Decl *decl)
|
||||
decl_poison(decl);
|
||||
continue;
|
||||
}
|
||||
if (!sema_analyse_struct_member(context, decl->strukt.members[i]))
|
||||
if (!sema_analyse_struct_member(context, member))
|
||||
{
|
||||
if (decl_ok(decl))
|
||||
{
|
||||
@@ -433,51 +487,6 @@ static inline bool sema_analyse_generic(Context *context, Decl *decl)
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void sema_set_struct_size(Decl *decl)
|
||||
{
|
||||
// TODO packed
|
||||
uint64_t size = 0;
|
||||
uint64_t alignment = 0;
|
||||
VECEACH(decl->strukt.members, i)
|
||||
{
|
||||
Decl *member = decl->strukt.members[i];
|
||||
Type *canonical = member->type->canonical;
|
||||
uint64_t member_size = type_size(canonical);
|
||||
uint64_t member_alignment = type_abi_alignment(canonical);
|
||||
assert(member_size > 0);
|
||||
// Add padding.
|
||||
if (member_alignment && (size % member_alignment))
|
||||
{
|
||||
size += member_alignment - size % member_alignment;
|
||||
}
|
||||
// Add size.
|
||||
size += member_size;
|
||||
if (member_alignment > alignment) alignment = member_alignment;
|
||||
}
|
||||
decl->strukt.abi_alignment = alignment;
|
||||
if (alignment && size % alignment)
|
||||
{
|
||||
size += alignment - size % alignment;
|
||||
}
|
||||
decl->strukt.size = size;
|
||||
}
|
||||
|
||||
static inline void sema_set_union_size(Decl *decl)
|
||||
{
|
||||
uint64_t size = 0;
|
||||
uint64_t alignment = 0;
|
||||
VECEACH(decl->strukt.members, i)
|
||||
{
|
||||
Decl *member = decl->strukt.members[i];
|
||||
Type *canonical = member->type->canonical;
|
||||
uint64_t member_size = type_size(canonical);
|
||||
uint64_t member_alignment = type_abi_alignment(canonical);
|
||||
if (member_size > size) size = member_size;
|
||||
if (member_alignment > alignment) alignment = member_alignment;
|
||||
}
|
||||
decl->strukt.abi_alignment = alignment;
|
||||
decl->strukt.size = size;
|
||||
}
|
||||
|
||||
bool sema_analyse_decl(Context *context, Decl *decl)
|
||||
{
|
||||
|
||||
@@ -335,17 +335,19 @@ static inline bool sema_expr_analyse_method_function(Context *context, Expr *exp
|
||||
}
|
||||
|
||||
|
||||
static Decl *strukt_recursive_search_member(Decl *strukt, const char *name, int *index)
|
||||
static Decl *strukt_recursive_search_member(Decl *strukt, const char *name)
|
||||
{
|
||||
VECEACH(strukt->strukt.members, i)
|
||||
{
|
||||
(*index)++;
|
||||
Decl *member = strukt->strukt.members[i];
|
||||
if (member->name == name) return member;
|
||||
if (!member->name && decl_is_struct_type(member))
|
||||
if (!member->name && type_is_structlike(member->type->canonical))
|
||||
{
|
||||
Decl *result = strukt_recursive_search_member(member, name, index);
|
||||
if (result) return result;
|
||||
Decl *result = strukt_recursive_search_member(member->type->canonical->decl, name);
|
||||
if (result)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
@@ -380,8 +382,7 @@ static inline bool sema_expr_analyse_access(Context *context, Type *to, Expr *ex
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
int index = -1;
|
||||
Decl *member = strukt_recursive_search_member(decl, expr->access_expr.sub_element.string, &index);
|
||||
Decl *member = strukt_recursive_search_member(decl, expr->access_expr.sub_element.string);
|
||||
if (!member)
|
||||
{
|
||||
SEMA_TOKEN_ERROR(expr->access_expr.sub_element, "There is no element '%s.%s'.", decl->name, expr->access_expr.sub_element.string);
|
||||
@@ -397,7 +398,7 @@ static inline bool sema_expr_analyse_access(Context *context, Type *to, Expr *ex
|
||||
expr->access_expr.parent = deref;
|
||||
}
|
||||
expr->type = member->type;
|
||||
expr->access_expr.index = index;
|
||||
expr->access_expr.ref = member;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user