Use correct sizes and alignments. Fix designated initializers and literals. Added todo

This commit is contained in:
Christoffer Lerno
2020-04-06 13:45:58 +02:00
parent 60c60a3205
commit 400c38b95b
23 changed files with 537 additions and 163 deletions

65
missing.txt Normal file
View File

@@ -0,0 +1,65 @@
Things missing:
* Attributes
- All types: @noreflect
- Struct: @packed, @aligned, @opaque
- Enums: @distinct, @noreflect
- Unions: @packed, @aligned, @opaque
- Functions: @inline, @reflect, @noreturn, @section, @unused, @used, @interrupt, @naked, @convention()
- Calls: @noinline
- Variables, parameters: @unused
- Constants, globals: @unused, @used, @section
* Designated initializer
- Array initializer
- Array range initializer { [1..2] = 2 }
* Initializers
- Array initializers
- Union initializers
* Asserts
- assert, $assert
- @unreachable
* Types
- Vararrays
- Strings
- Array
- Slice
- Values: size, alignment, name, qualifiedName
- Functions: offsetof
- Distinct types
- Simd types?
- Complex types?
- Subtype casts
- Bitstruct
- Enumset
- Typeid
- Union usage
* Expressions
- Disallow x >= 0 and x < 0 on unsigned types unless in a macro.
* Switch
- String switch
- Range case
* Functions
- Varargs
- C ABI
- Safe varargs
* Pre-post conditions
- Breakdown here
* Error handling
- Error unions
- Catch/try
- Function return channel
* Enum
- Values: min, max, array
- Functions: fomOrdinal, ordinal, fromName, name, fromFullName, fullName, fromQualifiedName, qualifiedName, <value>(), fromValue()

View File

@@ -2,16 +2,6 @@ module bar;
typedef int as Bob;
/* hello *//* there */
/+ why /+ you /* lucky +/ +/
// Whut
// Here
//
//---
/*
Hello
*/
struct Test
{
int a;
@@ -38,32 +28,6 @@ struct Teob
int oekfeo;
}
typedef long as Frob;
enum EnumTestAlias : Frob
{
VALUE1 = 4,
VALUE2
}
enum EnumTestDefault
{
VALUE,
VALUE2
}
enum EnumTestNoOverflowAfterLong : long
{
VALUE = 0x7FFF_FFFF_FFFF_FFFE,
VALUE_NO_EXCEED
}
enum EnumTestSmall : ushort
{
VALUE = 0xFF,
VALUE2 = 0xFFFF
}
enum EnumWithData : ushort (int a, char[] x, long b = 4)
{
// Currently the args are ignored TODO!
@@ -105,8 +69,8 @@ error Error
{
BLURB,
NO_SUCH_FILE,
}
error OtherError
{
FOO_BAR
@@ -128,6 +92,39 @@ enum Inf2 : byte
typedef Inf as BooInf;
struct TestStruct
{
int a;
}
struct TestStruct2
{
TestStruct a;
char xx;
TestStruct b;
int c;
}
union TestUnion
{
int a;
double f;
}
func TestStruct structTest(int i)
{
TestUnion tu;
/* TestStruct foo = { i };
TestStruct foo2 = { a = i };*/
TestStruct foo3 = TestStruct { i };
return foo3;
/* TestStruct2 bar = { c = 2 };
int x = 3 * i;
TestStruct2 bar2 = { b.a = x, a.a = x + 1 };
return bar2;*/
}
func void enumInferenceTest()
{
OtherError e = OtherError.FOO_BAR;

View File

@@ -0,0 +1,13 @@
module comments;
/* Span *//* style */
/+ Nested /+ Errors /* Inside +/ +/
// Single line
/*
Multiline span style
*/
func void test()
{
return;
}

View File

@@ -4,3 +4,28 @@ enum EnumTest : long
VALUE2
}
typedef long as Frob;
enum EnumTestAlias : Frob
{
VALUE1 = 4,
VALUE2
}
enum EnumTestDefault
{
VALUE,
VALUE2
}
enum EnumTestNoOverflowAfterLong : long
{
VALUE = 0x7FFF_FFFF_FFFF_FFFE,
VALUE_NO_EXCEED
}
enum EnumTestSmall : ushort
{
VALUE = 0xFF,
VALUE2 = 0xFFFF
}

View File

@@ -0,0 +1,12 @@
module errors;
error TheError
{
FOO_MISSING,
NO_SUCH_FILE,
}
error OtherError
{
BAR_OVERFLOWED
}

View File

View File

@@ -0,0 +1,5 @@
module typedefs;
typedef Loop as Loop2;
typedef Loop2 as Loop3;
typedef Loop3 as Loop;

View File

@@ -0,0 +1,14 @@
module typedefs;
// Standard case
typedef int as Foo;
// Nested resolution
typedef AType as BType;
typedef int as AType;
enum Bar : BType
{
A,
B
}

View File

@@ -551,12 +551,6 @@ void fprint_expr_recursive(FILE *file, Expr *expr, int indent)
fprint_expr_common(file, expr, indent + 1);
fprint_type_info_recursive(file, expr->type_access.type, indent + 1);
break;
case EXPR_STRUCT_VALUE:
fprintf_indented(file, indent, "(structvalue\n");
fprint_expr_common(file, expr, indent + 1);
fprint_type_info_recursive(file, expr->struct_value_expr.type, indent + 1);
fprint_expr_recursive(file, expr->struct_value_expr.init_expr, indent + 1);
break;
case EXPR_ACCESS:
fprintf_indented(file, indent, "(access .%s\n", expr->access_expr.sub_element.string);
fprint_expr_common(file, expr, indent + 1);
@@ -595,12 +589,27 @@ void fprint_expr_recursive(FILE *file, Expr *expr, int indent)
fprint_expr_recursive(file, expr->ternary_expr.else_expr, indent + 1);
break;
case EXPR_INITIALIZER_LIST:
fprintf_indented(file, indent, "(initializerlist\n");
fprintf_indented(file, indent, "(initializerlist ");
switch (expr->expr_initializer.init_type)
{
case INITIALIZER_UNKNOWN:
fprintf(file, "not-analyzed\n");
break;
case INITIALIZER_ZERO:
fprintf(file, "zero\n");
break;
case INITIALIZER_NORMAL:
fprintf(file, "normal\n");
break;
case INITIALIZER_DESIGNATED:
fprintf(file, "designated\n");
break;
}
fprint_expr_common(file, expr, indent + 1);
{
VECEACH(expr->initializer_expr, i)
VECEACH(expr->expr_initializer.initializer_expr, i)
{
fprint_expr_recursive(file, expr->initializer_expr[i], indent + 1);
fprint_expr_recursive(file, expr->expr_initializer.initializer_expr[i], indent + 1);
}
}
break;

View File

@@ -137,7 +137,7 @@ typedef struct
{
unsigned char bitsize;
unsigned char bytesize;
unsigned char min_alignment;
unsigned char abi_alignment;
unsigned char pref_alignment;
} TypeBuiltin;
@@ -226,7 +226,7 @@ typedef struct
typedef struct
{
uint32_t alignment;
uint32_t abi_alignment;
uint64_t size;
Decl **members;
} StructDecl;
@@ -500,6 +500,32 @@ typedef struct
Ast **stmts;
} ExprFuncBlock;
typedef enum
{
INITIALIZER_UNKNOWN,
INITIALIZER_ZERO,
INITIALIZER_DESIGNATED,
INITIALIZER_NORMAL
} InitializerType;
typedef struct
{
InitializerType init_type;
Expr** initializer_expr;
} ExprInitializer;
typedef struct _DesignatedInitPath
{
Decl *decl;
struct _DesignatedInitPath *sub_path;
} DesignatedInitPath;
typedef struct
{
DesignatedInitPath path;
Expr *value;
} ExprDesignatedInit;
struct _Expr
{
ExprKind expr_kind : 8;
@@ -507,6 +533,7 @@ struct _Expr
SourceRange span;
Type *type;
union {
ExprDesignatedInit designated_init_expr;
ExprCast cast_expr;
ExprConst const_expr;
ExprStructValue struct_value_expr;
@@ -522,7 +549,7 @@ struct _Expr
ExprAccess access_expr;
ExprIdentifier identifier_expr;
ExprType type_expr;
Expr** initializer_expr;
ExprInitializer expr_initializer;
Expr** expression_list;
ExprScope expr_scope;
ExprFuncBlock expr_block;
@@ -1133,6 +1160,7 @@ bool type_is_subtype(Type *type, Type *possible_subtype);
Type *type_find_common_ancestor(Type *left, Type *right);
const char *type_to_error_string(Type *type);
size_t type_size(Type *canonical);
size_t type_abi_alignment(Type *canonical);
void type_append_signature_name(Type *type, char *dst, size_t *offset);
Type *type_find_max_type(Type *type, Type *other);

View File

@@ -223,14 +223,13 @@ typedef enum
EXPR_SIZEOF,
EXPR_SUBSCRIPT,
EXPR_ACCESS,
EXPR_STRUCT_VALUE,
EXPR_STRUCT_INIT_VALUES,
EXPR_INITIALIZER_LIST,
EXPR_EXPRESSION_LIST,
EXPR_CAST,
EXPR_SCOPED_EXPR,
EXPR_MACRO_EXPR,
EXPR_EXPR_BLOCK,
EXPR_DESIGNATED_INIT,
} ExprKind;

View File

@@ -101,12 +101,11 @@ LLVMValueRef gencontext_emit_address(GenContext *context, Expr *expr)
case EXPR_POST_UNARY:
case EXPR_TYPE_ACCESS:
case EXPR_CALL:
case EXPR_STRUCT_VALUE:
case EXPR_STRUCT_INIT_VALUES:
case EXPR_INITIALIZER_LIST:
case EXPR_EXPRESSION_LIST:
case EXPR_CAST:
case EXPR_MACRO_EXPR:
case EXPR_DESIGNATED_INIT:
UNREACHABLE
}
UNREACHABLE
@@ -740,30 +739,55 @@ static inline LLVMValueRef gencontext_emit_expression_list_expr(GenContext *cont
return value;
}
static inline LLVMValueRef gencontext_emit_initializer_list_expr(GenContext *context, Expr *expr)
{
LLVMTypeRef type = llvm_type(expr->type);
LLVMValueRef value = LLVMGetUndef(type);
if (!vec_size(expr->initializer_expr))
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.alignment);
return ref;
LLVMConstInt(llvm_type(type_ulong), expr->type->decl->strukt.size, false), expr->type->decl->strukt.abi_alignment);
return value;
}
VECEACH(expr->initializer_expr, i)
Expr **elements = expr->expr_initializer.initializer_expr;
if (expr->expr_initializer.init_type == INITIALIZER_NORMAL)
{
LLVMValueRef init_value = gencontext_emit_expr(context, expr->initializer_expr[i]);
value = LLVMBuildInsertValue(context->builder, value, init_value, i, "literal");
VECEACH(elements, i)
{
LLVMValueRef init_value = gencontext_emit_expr(context, elements[i]);
value = LLVMBuildInsertValue(context->builder, value, init_value, i, "literal");
}
return value;
}
return value;
}
static inline LLVMValueRef gencontext_emit_struct_init_values_expr(GenContext *context, Expr *expr)
{
TODO
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)
@@ -803,6 +827,9 @@ LLVMValueRef gencontext_emit_expr(GenContext *context, Expr *expr)
{
case EXPR_POISONED:
UNREACHABLE
case EXPR_DESIGNATED_INIT:
// This is handled inside of initializer setup
UNREACHABLE
case EXPR_EXPR_BLOCK:
return gencontext_emit_expr_block(context, expr);
case EXPR_SCOPED_EXPR:
@@ -831,10 +858,6 @@ LLVMValueRef gencontext_emit_expr(GenContext *context, Expr *expr)
return gencontext_emit_call_expr(context, expr);
case EXPR_ACCESS:
return gencontext_emit_access_expr(context, expr);
case EXPR_STRUCT_VALUE:
return gencontext_emit_struct_value_expr(context, expr);
case EXPR_STRUCT_INIT_VALUES:
return gencontext_emit_struct_init_values_expr(context, expr);
case EXPR_INITIALIZER_LIST:
return gencontext_emit_initializer_list_expr(context, expr);
case EXPR_EXPRESSION_LIST:

View File

@@ -44,11 +44,11 @@ static LLVMValueRef gencontext_emit_decl(GenContext *context, Ast *ast)
{
Expr *expr = decl->var.init_expr;
// Quick path for empty initializer list
if (expr->expr_kind == EXPR_INITIALIZER_LIST && vec_size(expr->initializer_expr) == 0)
if (expr->expr_kind == EXPR_INITIALIZER_LIST && expr->expr_initializer.init_type == INITIALIZER_ZERO)
{
LLVMBuildMemSet(context->builder, decl->var.backend_ref, LLVMConstInt(llvm_type(type_byte), 0, false),
LLVMConstInt(llvm_type(type_ulong), expr->type->decl->strukt.size, false),
expr->type->decl->strukt.alignment);
expr->type->decl->strukt.abi_alignment);
return decl->var.backend_ref;
}

View File

@@ -226,5 +226,5 @@ 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.alignment = LLVMPreferredAlignmentOfType(target_data_layout(), type);
decl->strukt.abi_alignment = LLVMPreferredAlignmentOfType(target_data_layout(), type);
}

View File

@@ -249,8 +249,9 @@ Expr *parse_initializer(Context *context)
Expr *parse_initializer_list(Context *context)
{
Expr *initializer_list = EXPR_NEW_TOKEN(EXPR_INITIALIZER_LIST, context->tok);
initializer_list->expr_initializer.init_type = INITIALIZER_UNKNOWN;
CONSUME_OR(TOKEN_LBRACE, &poisoned_expr);
if (!parse_param_list(context, &initializer_list->initializer_expr, false)) return &poisoned_expr;
if (!parse_param_list(context, &initializer_list->expr_initializer.initializer_expr, false)) return &poisoned_expr;
CONSUME_OR(TOKEN_RBRACE, &poisoned_expr);
return initializer_list;
}

View File

@@ -1033,7 +1033,9 @@ bool parse_struct_body(Context *context, Decl *parent, Decl *visible_parent)
decl_poison(other);
decl_poison(member);
}
unsigned index = vec_size(parent->strukt.members);
parent->strukt.members = VECADD(parent->strukt.members, member);
member->var.id = index;
advance(context);
if (context->tok.type != TOKEN_COMMA) break;
}
@@ -1994,11 +1996,7 @@ Expr *parse_type_identifier_with_path(Context *context, Path *path)
RANGE_EXTEND_PREV(type);
if (context->tok.type == TOKEN_LBRACE)
{
Expr *expr = EXPR_NEW_TOKEN(EXPR_STRUCT_VALUE, context->tok);
expr->struct_value_expr.type = type;
expr->struct_value_expr.init_expr = TRY_EXPR_OR(parse_initializer_list(context), &poisoned_expr);
return expr;
return TRY_EXPR_OR(parse_initializer_list(context), &poisoned_expr);
}
EXPECT_OR(TOKEN_DOT, &poisoned_expr);
return parse_type_access(context, type);

View File

@@ -40,6 +40,8 @@ static inline bool sema_analyse_error(Context *context __unused, Decl *decl)
static inline bool sema_analyse_struct_member(Context *context, Decl *decl)
{
assert(decl->resolve_status == RESOLVE_NOT_DONE);
decl->resolve_status = RESOLVE_RUNNING;
if (decl->decl_kind == DECL_STRUCT || decl->decl_kind == DECL_UNION)
{
DEBUG_LOG("Beginning analysis of inner struct/union");
@@ -74,6 +76,7 @@ static inline bool sema_analyse_struct_member(Context *context, Decl *decl)
}
decl->type = decl->var.type_info->type;
assert(decl->var.type_info->type);
decl->resolve_status = RESOLVE_DONE;
return true;
}
@@ -430,6 +433,52 @@ 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)
{
if (decl->resolve_status == RESOLVE_DONE) return decl_ok(decl);
@@ -450,9 +499,13 @@ bool sema_analyse_decl(Context *context, Decl *decl)
if (!sema_analyse_throws(context, decl)) return decl_poison(decl);
break;
case DECL_STRUCT:
if (!sema_analyse_struct_union(context, decl)) return decl_poison(decl);
sema_set_struct_size(decl);
decl_set_external_name(decl);
break;
case DECL_UNION:
if (!sema_analyse_struct_union(context, decl)) return decl_poison(decl);
llvm_set_struct_size_alignment(decl);
sema_set_union_size(decl);
decl_set_external_name(decl);
break;
case DECL_FUNC:

View File

@@ -280,15 +280,6 @@ static inline bool sema_expr_analyse_call(Context *context, Type *to, Expr *expr
}
}
static inline bool sema_expr_analyse_struct_value(Context *context, Type *to, Expr *expr)
{
TODO
}
static inline bool sema_expr_analyse_struct_init_values(Context *context, Type *to, Expr *expr)
{
TODO
}
static inline bool sema_expr_analyse_subscript(Context *context, Type *to, Expr *expr)
{
@@ -492,6 +483,7 @@ static Decl *sema_analyse_init_identifier(Context *context, Decl *strukt, Expr *
expr->resolve_status = RESOLVE_RUNNING;
expr->identifier_expr.decl = sema_analyse_init_identifier_string(context, strukt, expr->identifier_expr.identifier);
expr->resolve_status = RESOLVE_DONE;
expr->type = expr->identifier_expr.decl->type;
return expr->identifier_expr.decl;
}
@@ -507,6 +499,7 @@ static Decl *sema_analyse_init_access(Context *context, Decl *strukt, Expr *acce
}
decl = access_expr->access_expr.ref = sema_analyse_init_identifier_string(context, decl->type->decl, access_expr->access_expr.sub_element.string);
access_expr->resolve_status = RESOLVE_DONE;
access_expr->type = decl->type;
return decl;
}
@@ -534,74 +527,189 @@ static Decl *sema_analyse_init_path(Context *context, Decl *strukt, Expr *expr)
}
}
static bool sema_expr_analyse_designated_init(Context *context, DesignatedInitPath *path, Decl *top, Expr *path_expr);
typedef enum
static bool sema_expr_analyse_designated_init_ident(Context *context, DesignatedInitPath *path, Decl *top, const char *name)
{
INIT_SEMA_ERROR,
INIT_SEMA_NOT_FOUND,
INIT_SEMA_OK
} InitSemaResult;
static InitSemaResult sema_expr_analyse_struct_named_initializer_list(Context *context, Decl *assigned, Expr *expr_list)
{
VECEACH(expr_list->initializer_expr, i)
// 3. Loop through the members.
Decl **members = top->strukt.members;
VECEACH(members, i)
{
Expr *expr = expr_list->initializer_expr[i];
Decl *member = members[i];
if (member->name == name)
{
// 4. If found, set this to the current path.
(*path) = (DesignatedInitPath) { .decl = member, .sub_path = NULL };
// 5. And we're done!
return true;
}
// 6. We might encounter anonymous members. Treat this as a possible "match"
if (!member->name)
{
DesignatedInitPath anon_path;
bool found = sema_expr_analyse_designated_init_ident(context, &anon_path, member, name);
if (found)
{
// 7. If found, create a copy path.
DesignatedInitPath *path_copy = malloc_arena(sizeof(DesignatedInitPath));
*path_copy = anon_path;
(*path) = (DesignatedInitPath) { .decl = member, .sub_path = path_copy };
return true;
}
}
}
return false;
}
static bool sema_expr_analyse_designated_init(Context *context, DesignatedInitPath *path, Decl *top, Expr *path_expr)
{
// Our expression will look like this for a.b[3].c = ...
// access(subscript(access(identifier))), now we need to reverse that.
switch (path_expr->expr_kind)
{
case EXPR_IDENTIFIER:
// Resolving for an identifier:
// 1. Can't be a path attached.
if (path_expr->identifier_expr.path) return false;
// 2. Ensure it's a union or struct
if (!decl_is_struct_type(top)) return false;
return sema_expr_analyse_designated_init_ident(context, path, top, path_expr->identifier_expr.identifier);
case EXPR_ACCESS:
// Resolve for access:
// 1. Resolve the parent path:
if (!sema_expr_analyse_designated_init(context, path, top, path_expr->access_expr.parent)) return false;
// 2. Our new top is now lowest init path.
while (path->sub_path)
{
path = path->sub_path;
}
top = path->decl;
// 3. Do an analysis with the identifier:
path->sub_path = malloc_arena(sizeof(DesignatedInitPath));
return sema_expr_analyse_designated_init_ident(context,
path->sub_path,
top->type->decl,
path_expr->access_expr.sub_element.string);
case EXPR_SUBSCRIPT:
// Resolve for subscript:
// 1. Resolve the parent path:
if (!sema_expr_analyse_designated_init(context, path, top, path_expr->subscript_expr.expr)) return false;
// 2. Our new top is now lowest init path.
while (path->sub_path)
{
path = path->sub_path;
}
top = path->decl;
TODO // Analyse index etc.
default:
return false;
}
}
static bool sema_expr_analyse_struct_designated_initializer_list(Context *context, Decl *assigned, Expr *expr_list)
{
assert(expr_list->expr_initializer.init_type == INITIALIZER_UNKNOWN);
VECEACH(expr_list->expr_initializer.initializer_expr, i)
{
Expr *expr = expr_list->expr_initializer.initializer_expr[i];
if (expr->expr_kind != EXPR_BINARY && expr->binary_expr.operator != BINARYOP_ASSIGN)
{
if (i != 0)
{
SEMA_ERROR(expr, "Named and non-named initializers are not allowed together, please choose one or the other.");
return INIT_SEMA_ERROR;
return false;
}
// If there is an unexpected expression and no previous element then this is a normal initializer list.
return INIT_SEMA_NOT_FOUND;
expr_list->expr_initializer.init_type = INITIALIZER_NORMAL;
return true;
}
Expr *path = expr->binary_expr.left;
Expr *path_expr = expr->binary_expr.left;
Expr *value = expr->binary_expr.right;
Decl *result = sema_analyse_init_path(context, assigned, path);
if (!result)
DesignatedInitPath path;
if (!sema_expr_analyse_designated_init(context, &path, assigned, path_expr))
{
if (i != 0)
{
SEMA_ERROR(path, "Unexpected element when initializing '%s', did you get the name right?", assigned->name);
return INIT_SEMA_ERROR;
SEMA_ERROR(path_expr, "Unexpected element when initializing '%s', did you get the name right?", assigned->name);
return false;
}
return INIT_SEMA_NOT_FOUND;
expr_list->expr_initializer.init_type = INITIALIZER_NORMAL;
return true;
}
if (!sema_analyse_expr_of_required_type(context, result->type, value)) return INIT_SEMA_ERROR;
// Walk down to the last decl.
DesignatedInitPath *init_path = &path;
while (init_path->sub_path) init_path = init_path->sub_path;
if (!sema_analyse_expr_of_required_type(context, init_path->decl->type, value)) return false;
// Destruct the expression and replace.
expr->designated_init_expr.value = value; // Do this first!
expr->resolve_status = RESOLVE_DONE;
expr->designated_init_expr.path = path;
expr->expr_kind = EXPR_DESIGNATED_INIT;
expr->type = init_path->decl->type;
}
return INIT_SEMA_OK;
expr_list->expr_initializer.init_type = INITIALIZER_DESIGNATED;
return true;
}
static inline bool sema_expr_analyse_struct_initializer_list(Context *context, Type *assigned, Expr *expr)
{
expr->type = assigned;
Decl **members = assigned->decl->strukt.members;
unsigned size = vec_size(members);
// Zero size init will initialize to empty.
if (size == 0) return true;
InitSemaResult result = sema_expr_analyse_struct_named_initializer_list(context, assigned->decl, expr);
if (result == INIT_SEMA_ERROR) return false;
if (result == INIT_SEMA_OK)
// Zero size init will initialize to empty.
if (size == 0)
{
TODO
expr->expr_initializer.init_type = INITIALIZER_ZERO;
return true;
}
if (!sema_expr_analyse_struct_designated_initializer_list(context, assigned->decl, expr)) return false;
// If we already parsed this.
if (expr->expr_initializer.init_type == INITIALIZER_DESIGNATED) return true;
Expr **elements = expr->expr_initializer.initializer_expr;
assert(expr->expr_initializer.init_type == INITIALIZER_NORMAL);
if (assigned->type_kind == TYPE_UNION)
{
SEMA_ERROR(expr->initializer_expr[0], "Initializer list for unions must use named initializers, e.g. { a = 4 }");
SEMA_ERROR(elements[0], "Initializer list for unions must use named initializers, e.g. { a = 4 }");
return false;
}
if (size < vec_size(expr->initializer_expr))
VECEACH(elements, i)
{
SEMA_ERROR(expr->initializer_expr[size], "Too many elements in initializer, expected only %d.", size);
if (i >= size)
{
SEMA_ERROR(elements[size], "Too many elements in initializer, expected only %d.", size);
return false;
}
if (!sema_analyse_expr_of_required_type(context, members[i]->type, elements[i])) return false;
}
if (size > vec_size(elements))
{
SEMA_ERROR(elements[vec_size(elements) - 1], "Too few elements in initializer, expected %d.", size);
return false;
}
VECEACH(expr->initializer_expr, i)
{
if (!sema_analyse_expr_of_required_type(context, members[i]->type, expr->initializer_expr[i])) return false;
}
expr->type = assigned;
return true;
}
@@ -1910,6 +2018,7 @@ static Expr *expr_shallow_copy(Expr *source)
return copy;
}
static Expr **expr_copy_expr_list_from_macro(Context *context, Expr *macro, Expr **expr_list);
static Expr *expr_copy_from_macro(Context *context, Expr *macro, Expr *source_expr);
static Ast *ast_copy_from_macro(Context *context, Expr *macro, Ast *source);
@@ -1968,6 +2077,9 @@ static Expr *expr_copy_from_macro(Context *context, Expr *macro, Expr *source_ex
Expr *expr = expr_shallow_copy(source_expr);
switch (source_expr->expr_kind)
{
case EXPR_DESIGNATED_INIT:
// This type of expression is only created after analysis.
UNREACHABLE
case EXPR_EXPR_BLOCK:
ast_copy_list_from_macro(context, macro, &expr->expr_block.stmts);
return expr;
@@ -2017,15 +2129,8 @@ static Expr *expr_copy_from_macro(Context *context, Expr *macro, Expr *source_ex
case EXPR_ACCESS:
EXPR_COPY(expr->access_expr.parent);
return expr;
case EXPR_STRUCT_VALUE:
expr->struct_value_expr.type = type_info_copy_from_macro(context, macro, expr->struct_value_expr.type);
EXPR_COPY(expr->struct_value_expr.init_expr);
return expr;
case EXPR_STRUCT_INIT_VALUES:
TODO
return expr;
case EXPR_INITIALIZER_LIST:
expr->initializer_expr = expr_copy_expr_list_from_macro(context, macro, expr->initializer_expr);
expr->expr_initializer.initializer_expr = expr_copy_expr_list_from_macro(context, macro, expr->expr_initializer.initializer_expr);
return expr;
case EXPR_EXPRESSION_LIST:
expr->expression_list = expr_copy_expr_list_from_macro(context, macro, expr->expression_list);
@@ -2426,6 +2531,7 @@ static inline bool sema_analyse_expr_dispatch(Context *context, Type *to, Expr *
case EXPR_POISONED:
return false;
case EXPR_SCOPED_EXPR:
case EXPR_DESIGNATED_INIT:
UNREACHABLE
case EXPR_EXPR_BLOCK:
return sema_expr_analyse_expr_block(context, to, expr);
@@ -2457,10 +2563,6 @@ static inline bool sema_analyse_expr_dispatch(Context *context, Type *to, Expr *
return sema_expr_analyse_subscript(context, to, expr);
case EXPR_ACCESS:
return sema_expr_analyse_access(context, to, expr);
case EXPR_STRUCT_VALUE:
return sema_expr_analyse_struct_value(context, to, expr);
case EXPR_STRUCT_INIT_VALUES:
return sema_expr_analyse_struct_init_values(context, to, expr);
case EXPR_INITIALIZER_LIST:
return sema_expr_analyse_initializer_list(context, to, expr);
case EXPR_CAST:

View File

@@ -109,6 +109,7 @@ void target_setup()
LLVMTypeRef float_type = LLVMFloatType();
LLVMTypeRef double_type = LLVMDoubleType();
LLVMTypeRef quad_type = LLVMFP128Type();
LLVMTypeRef pointer_type = LLVMPointerType(int_type, 0);
build_target.align_byte = LLVMABIAlignmentOfType(build_target.llvm_data_layout, byte_type);
build_target.align_short = LLVMABIAlignmentOfType(build_target.llvm_data_layout, short_type);
build_target.align_int = LLVMABIAlignmentOfType(build_target.llvm_data_layout, int_type);
@@ -116,6 +117,7 @@ void target_setup()
build_target.align_f128 = LLVMABIAlignmentOfType(build_target.llvm_data_layout, quad_type);
build_target.align_double = LLVMABIAlignmentOfType(build_target.llvm_data_layout, double_type);
build_target.align_float = LLVMABIAlignmentOfType(build_target.llvm_data_layout, float_type);
build_target.align_pointer = LLVMABIAlignmentOfType(build_target.llvm_data_layout, pointer_type);
build_target.little_endian = LLVMByteOrder(build_target.llvm_data_layout) == LLVMLittleEndian;
build_target.width_c_short = os_target_c_type_bits(build_target.os, build_target.arch, CTYPE_SHORT);
build_target.width_c_int = os_target_c_type_bits(build_target.os, build_target.arch, CTYPE_INT);

View File

@@ -151,15 +151,15 @@ typedef struct
bool asm_supported;
bool float_128;
bool float_16;
unsigned align_min_pointer;
unsigned align_min_byte;
unsigned align_min_short;
unsigned align_min_int;
unsigned align_min_long;
unsigned align_min_half;
unsigned align_min_float;
unsigned align_min_double;
unsigned align_min_f128;
unsigned align_pref_pointer;
unsigned align_pref_byte;
unsigned align_pref_short;
unsigned align_pref_int;
unsigned align_pref_long;
unsigned align_pref_half;
unsigned align_pref_float;
unsigned align_pref_double;
unsigned align_pref_f128;
unsigned align_pointer;
unsigned align_byte;
unsigned align_short;

View File

@@ -198,29 +198,18 @@ size_t type_size(Type *canonical)
case TYPE_META_TYPE:
return 0;
case TYPE_ENUM:
return type_size(canonical->decl->enums.type_info->type->canonical);
return canonical->decl->enums.type_info->type->canonical->builtin.bytesize;
case TYPE_ERROR:
return type_error->canonical->builtin.bytesize;
case TYPE_STRUCT:
case TYPE_UNION:
case TYPE_ERROR:
TODO
return canonical->decl->strukt.size;
case TYPE_VOID:
return 1;
case TYPE_BOOL:
case TYPE_I8:
case TYPE_I16:
case TYPE_I32:
case TYPE_I64:
case TYPE_U8:
case TYPE_U16:
case TYPE_U32:
case TYPE_U64:
case TYPE_F32:
case TYPE_F64:
case ALL_INTS:
case ALL_FLOATS:
return canonical->builtin.bytesize;
case TYPE_IXX:
return 8;
case TYPE_FXX:
return 8;
case TYPE_FUNC:
case TYPE_POINTER:
case TYPE_VARARRAY:
@@ -233,7 +222,44 @@ size_t type_size(Type *canonical)
case TYPE_ERROR_UNION:
TODO
}
TODO
UNREACHABLE
}
size_t type_abi_alignment(Type *canonical)
{
assert(canonical && canonical->canonical == canonical);
switch (canonical->type_kind)
{
case TYPE_POISONED:
case TYPE_TYPEDEF:
case TYPE_VOID:
UNREACHABLE;
case TYPE_META_TYPE:
return 0;
case TYPE_ENUM:
return canonical->decl->enums.type_info->type->canonical->builtin.abi_alignment;
case TYPE_ERROR:
return type_error->canonical->builtin.abi_alignment;
case TYPE_STRUCT:
case TYPE_UNION:
return canonical->decl->strukt.abi_alignment;
case TYPE_BOOL:
case ALL_INTS:
case ALL_FLOATS:
return canonical->builtin.abi_alignment;
case TYPE_FUNC:
case TYPE_POINTER:
case TYPE_VARARRAY:
case TYPE_STRING:
return t_usz.canonical->builtin.abi_alignment;
case TYPE_ARRAY:
return type_abi_alignment(canonical->array.base);
case TYPE_SUBARRAY:
TODO
case TYPE_ERROR_UNION:
TODO
}
UNREACHABLE
}
static inline void create_type_cache(Type *canonical_type)
@@ -375,7 +401,7 @@ static void type_create(const char *name, Type *location, TypeKind kind, unsigne
.type_kind = kind,
.builtin.bytesize = (bitsize + 7) / 8,
.builtin.bitsize = bitsize,
.builtin.min_alignment = align,
.builtin.abi_alignment = align,
.builtin.pref_alignment = pref_align,
.name = name,
.canonical = location,
@@ -403,7 +429,7 @@ void builtin_setup(Target *target)
type_string.type_kind = TYPE_STRING;
*/
#define DEF_TYPE(_name, _shortname, _type, _bits, _align) \
type_create(#_name, &_shortname, _type, _bits, target->align_min_ ## _align, target->align_ ## _align)
type_create(#_name, &_shortname, _type, _bits, target->align_ ## _align, target->align_pref_ ## _align)
DEF_TYPE(bool, t_u1, TYPE_BOOL, 1, byte);
DEF_TYPE(float, t_f32, TYPE_F32, 32, float);
@@ -424,7 +450,7 @@ type_create(#_name, &_shortname, _type, _bits, target->align_min_ ## _align, tar
#undef DEF_TYPE
type_create("void*", &t_voidstar, TYPE_POINTER, target->width_pointer, target->align_min_pointer, target->align_pointer);
type_create("void*", &t_voidstar, TYPE_POINTER, target->width_pointer, target->align_pref_pointer, target->align_pointer);
create_type_cache(type_void);
type_void->type_cache[0] = &t_voidstar;
t_voidstar.pointer = type_void;

View File

@@ -42,6 +42,7 @@ TargetInfo target_info_new()
.asm_supported = false,
.float_128 = false,
.float_16 = false,
.align_pointer = 8,
.align_byte = 8,
.align_c_int = 32,
.align_c_long = 32,

View File

@@ -267,6 +267,7 @@ static inline void* _expand(void *vec, size_t element_size)
#define VECEACH(_vec, _index) \
for (unsigned _index = 0, __vecsize = vec_size(_vec); _index < __vecsize; _index++)
#define VECNEW(_type, _capacity) ((_type *)(_vec_new(sizeof(_type), _capacity) + 1))
#define VECADD(_vec, _value) \
({ \