Flexible array member added, zero sized structs removed.

This commit is contained in:
Christoffer Lerno
2021-12-14 18:53:23 +01:00
parent 5ddbf50e83
commit 680b077eb1
30 changed files with 252 additions and 35 deletions

View File

@@ -26,7 +26,3 @@ struct VarArrayHeader
}
struct VarArrayContainer
{
}

View File

@@ -268,6 +268,8 @@ bool type_is_homogenous_aggregate(Type *type, Type **base, unsigned *elements)
if (type_size(*base) * *elements != type_size(type)) return false;
}
goto TYPECHECK;
case TYPE_FLEXIBLE_ARRAY:
return false;
case TYPE_ARRAY:
// Empty arrays? Not homogenous.
if (type->array.len == 0) return false;

View File

@@ -100,7 +100,7 @@ typedef enum
CONST_INIT_ARRAY,
CONST_INIT_ARRAY_FULL,
CONST_INIT_ARRAY_VALUE,
} ConstInitType;
} ConstInitType;
typedef struct ConstInitializer_
@@ -2054,6 +2054,7 @@ Type *type_get_ptr(Type *ptr_type);
Type *type_get_ptr_recurse(Type *ptr_type);
Type *type_get_subarray(Type *arr_type);
Type *type_get_inferred_array(Type *arr_type);
Type *type_get_flexible_array(Type *arr_type);
Type *type_get_failable(Type *failable_type);
Type *type_get_vector(Type *vector_type, unsigned len);
Type *type_get_vector_bool(Type *original_type);

View File

@@ -554,6 +554,7 @@ typedef enum
TYPE_ARRAY,
TYPE_SUBARRAY,
TYPE_INFERRED_ARRAY,
TYPE_FLEXIBLE_ARRAY,
TYPE_UNTYPED_LIST,
TYPE_FAILABLE,
TYPE_FAILABLE_ANY,

View File

@@ -97,6 +97,8 @@ static void header_print_type(FILE *file, Type *type)
case TYPE_ERRTYPE:
OUTPUT("enum %s__", type->decl->external_name);
return;
case TYPE_FLEXIBLE_ARRAY:
TODO
case TYPE_FUNC:
TODO
case TYPE_STRUCT:

View File

@@ -328,6 +328,7 @@ void llvm_emit_ptr_from_array(GenContext *c, BEValue *value)
return;
case TYPE_ARRAY:
case TYPE_VECTOR:
case TYPE_FLEXIBLE_ARRAY:
return;
case TYPE_SUBARRAY:
{

View File

@@ -442,6 +442,7 @@ static void x64_classify(Type *type, ByteSize offset_base, X64Class *lo_class, X
case TYPE_UNION:
x64_classify_struct_union(type, offset_base, current, lo_class, hi_class, named);
break;
case TYPE_FLEXIBLE_ARRAY:
case TYPE_ARRAY:
x64_classify_array(type, offset_base, current, lo_class, hi_class, named);
break;
@@ -574,6 +575,8 @@ AbiType *x64_get_int_type_at_offset(Type *type, unsigned offset, Type *source_ty
if (offset < 8) return abi_type_new_plain(type_voidptr);
if (offset < 16) return abi_type_new_plain(type_ulong);
break;
case TYPE_FLEXIBLE_ARRAY:
UNREACHABLE
case TYPE_ARRAY:
{
Type *element = type->array.base;

View File

@@ -120,6 +120,7 @@ static bool x86_should_return_type_in_reg(Type *type)
case CT_TYPES:
case TYPE_FAILABLE:
case TYPE_FAILABLE_ANY:
case TYPE_FLEXIBLE_ARRAY:
UNREACHABLE
case ALL_INTS:
case ALL_FLOATS:
@@ -597,6 +598,7 @@ static ABIArgInfo *x86_classify_argument(CallABI call, Regs *regs, Type *type)
case TYPE_FAILABLE:
case TYPE_FAILABLE_ANY:
case CT_TYPES:
case TYPE_FLEXIBLE_ARRAY:
UNREACHABLE
case ALL_FLOATS:
case ALL_INTS:

View File

@@ -543,6 +543,7 @@ static inline LLVMMetadataRef llvm_get_debug_type_internal(GenContext *c, Type *
case TYPE_TYPEDEF:
return type->backend_debug_type = llvm_debug_typedef_type(c, type);
case TYPE_ARRAY:
case TYPE_FLEXIBLE_ARRAY:
return type->backend_debug_type = llvm_debug_array_type(c, type);
case TYPE_SUBARRAY:
return type->backend_debug_type = llvm_debug_subarray_type(c, type);

View File

@@ -491,6 +491,13 @@ static inline void llvm_emit_subscript_addr_with_base(GenContext *c, BEValue *re
case TYPE_POINTER:
llvm_value_set_address(result, llvm_emit_pointer_inbounds_gep_raw(c, llvm_get_pointee_type(c, parent->type), parent->value, index->value), type->pointer);
return;
case TYPE_FLEXIBLE_ARRAY:
{
AlignSize alignment;
LLVMValueRef ptr = llvm_emit_array_gep_raw_index(c, parent->value, llvm_get_type(c, type), index->value, parent->alignment, &alignment);
llvm_value_set_address_align(result, ptr, type->array.base, alignment);
return;
}
case TYPE_ARRAY:
case TYPE_VECTOR:
// TODO vector
@@ -3861,6 +3868,7 @@ static void llvm_expand_type_to_args(GenContext *context, Type *param_type, LLVM
case TYPE_FAILABLE:
case CT_TYPES:
case TYPE_FAILABLE_ANY:
case TYPE_FLEXIBLE_ARRAY:
UNREACHABLE
break;
case TYPE_BOOL:

View File

@@ -352,6 +352,7 @@ LLVMTypeRef llvm_get_type(GenContext *c, Type *any_type)
case TYPE_POINTER:
return any_type->backend_type = llvm_type_from_ptr(c, any_type);
case TYPE_ARRAY:
case TYPE_FLEXIBLE_ARRAY:
return any_type->backend_type = llvm_type_from_array(c, any_type);
case TYPE_SUBARRAY:
{

View File

@@ -389,6 +389,7 @@ CastKind cast_to_bool_kind(Type *type)
case TYPE_FAILABLE:
case TYPE_ANY:
case TYPE_FAILABLE_ANY:
case TYPE_FLEXIBLE_ARRAY:
return CAST_ERROR;
}
UNREACHABLE
@@ -481,6 +482,8 @@ bool cast_may_explicit(Type *from_type, Type *to_type, bool ignore_failability,
case TYPE_ERRTYPE:
// Allow MyError.A -> error, to an integer or to bool
return to_type->type_kind == TYPE_ANYERR || type_is_integer(to_type) || to_type == type_bool;
case TYPE_FLEXIBLE_ARRAY:
return false;
case TYPE_ARRAY:
if (to_kind == TYPE_VECTOR)
{
@@ -1260,6 +1263,8 @@ static bool cast_inner(Expr *expr, Type *from_type, Type *to, Type *to_type)
if (to == type_bool) return err_to_bool(expr, to_type);
if (type_is_integer(to)) return insert_cast(expr, CAST_ERINT, to_type);
break;
case TYPE_FLEXIBLE_ARRAY:
return false;
case TYPE_ARRAY:
if (to->type_kind == TYPE_VECTOR) return insert_cast(expr, CAST_ARRVEC, to_type);
FALLTHROUGH;

View File

@@ -83,19 +83,30 @@ static inline bool sema_analyse_struct_member(Context *context, Decl *decl)
}
if (decl->name) sema_add_member(context, decl);
}
switch (decl->decl_kind)
{
case DECL_VAR:
assert(decl->var.kind == VARDECL_MEMBER);
decl->resolve_status = RESOLVE_RUNNING;
if (!sema_resolve_type_info(context, decl->var.type_info)) return decl_poison(decl);
if (!sema_resolve_type_info_maybe_inferred(context, decl->var.type_info, true)) return decl_poison(decl);
decl->type = decl->var.type_info->type;
decl->resolve_status = RESOLVE_DONE;
Type *member_type = type_flatten_distinct(decl->type);
if (member_type->type_kind == TYPE_ARRAY)
{
if (member_type->array.len == 0)
{
SEMA_ERROR(decl, "Zero length arrays are not valid members.");
return false;
}
}
return true;
case DECL_STRUCT:
case DECL_UNION:
case DECL_BITSTRUCT:
return sema_analyse_decl(context, decl);
if (!sema_analyse_decl(context, decl)) return false;
return true;
default:
UNREACHABLE
}
@@ -107,6 +118,7 @@ static bool sema_analyse_union_members(Context *context, Decl *decl, Decl **memb
MemberIndex max_alignment_element = 0;
AlignSize max_alignment = 0;
bool has_named_parameter = false;
VECEACH(members, i)
{
Decl *member = members[i];
@@ -124,7 +136,11 @@ static bool sema_analyse_union_members(Context *context, Decl *decl, Decl **memb
}
continue;
}
if (member->type->type_kind == TYPE_INFERRED_ARRAY)
{
SEMA_ERROR(member, "Flexible array members not allowed in unions.");
return false;
}
AlignSize member_alignment = type_abi_alignment(member->type);
ByteSize member_size = type_size(member->type);
assert(member_size <= MAX_TYPE_SIZE);
@@ -195,13 +211,14 @@ static bool sema_analyse_union_members(Context *context, Decl *decl, Decl **memb
static bool sema_analyse_struct_members(Context *context, Decl *decl, Decl **members)
{
// Default alignment is 1 even if the it is empty.
// Default alignment is 1 even if it is empty.
AlignSize natural_alignment = 1;
bool is_unaligned = false;
AlignSize size = 0;
AlignSize offset = 0;
bool is_packed = decl->is_packed;
VECEACH(members, i)
unsigned member_count = vec_size(members);
for (unsigned i = 0; i < member_count; i++)
{
Decl *member = decl->strukt.members[i];
if (!decl_ok(member))
@@ -218,6 +235,31 @@ static bool sema_analyse_struct_members(Context *context, Decl *decl, Decl **mem
}
continue;
}
Type *member_type = type_flatten_distinct(member->type);
if (member_type->type_kind == TYPE_STRUCT && member_type->decl->has_variable_array)
{
if (i != member_count - 1)
{
SEMA_ERROR(member, "A struct member with a flexible array must be the last element.");
return false;
}
decl->has_variable_array = true;
}
if (member_type->type_kind == TYPE_INFERRED_ARRAY)
{
if (i != member_count - 1)
{
SEMA_ERROR(member, "The flexible array member must be the last element.");
return false;
}
if (i == 0)
{
SEMA_ERROR(member, "The flexible array member cannot be the only element.");
return false;
}
member->type = type_get_flexible_array(member->type->array.base);
decl->has_variable_array = true;
}
if (!decl_ok(decl)) return false;
@@ -366,6 +408,12 @@ static bool sema_analyse_struct_union(Context *context, Decl *decl)
DEBUG_LOG("Beginning analysis of %s.", decl->name ? decl->name : "anon");
bool success;
Decl **members = decl->strukt.members;
if (!vec_size(members))
{
SEMA_ERROR(decl, decl->decl_kind == DECL_UNION ? "Zero sized unions are not permitted." : "Zero sized structs are not permitted.");
return false;
}
if (decl->name)
{
SCOPE_START
@@ -663,7 +711,13 @@ static inline bool sema_analyse_typedef(Context *context, Decl *decl)
return true;
}
if (!sema_resolve_type_info(context, decl->typedef_decl.type_info)) return false;
decl->type->canonical = decl->typedef_decl.type_info->type->canonical;
Type *type = decl->typedef_decl.type_info->type->canonical;
if (type == type_anyerr || type == type_any)
{
SEMA_ERROR(decl->typedef_decl.type_info, "%s may not be aliased.", type_quoted_error_string(type));
return false;
}
decl->type->canonical = type;
// Do we need anything else?
return true;
}
@@ -687,6 +741,7 @@ static inline bool sema_analyse_distinct(Context *context, Decl *decl)
case TYPE_TYPEDEF:
case TYPE_DISTINCT:
case CT_TYPES:
case TYPE_FLEXIBLE_ARRAY:
UNREACHABLE
return false;
case TYPE_FAILABLE_ANY:

View File

@@ -2299,6 +2299,7 @@ static bool expr_check_index_in_range(Context *context, Type *type, Expr *index_
switch (type->type_kind)
{
case TYPE_POINTER:
case TYPE_FLEXIBLE_ARRAY:
assert(!from_end);
return true;
case TYPE_ARRAY:

View File

@@ -78,7 +78,15 @@ static inline bool sema_resolve_array_type(Context *context, TypeInfo *type, boo
return type_info_poison(type);
}
}
Type *distinct_base = type_flatten_distinct(type->array.base->type);
if (distinct_base->type_kind == TYPE_STRUCT)
{
if (distinct_base->decl->has_variable_array)
{
SEMA_ERROR(type, "Arrays of structs with flexible array members is not allowed.");
return type_info_poison(type);
}
}
switch (type->kind)
{
case TYPE_INFO_SUBARRAY:
@@ -105,6 +113,7 @@ static inline bool sema_resolve_array_type(Context *context, TypeInfo *type, boo
UNREACHABLE
}
assert(!type->array.len || type->array.len->expr_kind == EXPR_CONST);
if (type->array.base)
type->resolve_status = RESOLVE_DONE;
return true;
}
@@ -211,6 +220,7 @@ bool sema_resolve_type(Context *context, Type *type)
case TYPE_ARRAY:
case TYPE_SUBARRAY:
case TYPE_INFERRED_ARRAY:
case TYPE_FLEXIBLE_ARRAY:
return sema_resolve_type(context, type->array.base);
case TYPE_FAILABLE:
return sema_resolve_type(context, type->failable);

View File

@@ -51,9 +51,10 @@ static AlignSize max_alignment_vector;
#define PTR_OFFSET 0
#define INFERRED_ARRAY_OFFSET 1
#define SUB_ARRAY_OFFSET 2
#define FAILABLE_OFFSET 3
#define ARRAY_OFFSET 4
#define FLEXIBLE_ARRAY_OFFSET 2
#define SUB_ARRAY_OFFSET 3
#define FAILABLE_OFFSET 4
#define ARRAY_OFFSET 5
Type *type_cint(void)
{
@@ -149,6 +150,7 @@ const char *type_to_error_string(Type *type)
asprintf(&buffer, "%s[%llu]", type_to_error_string(type->array.base), (unsigned long long)type->array.len);
return buffer;
case TYPE_INFERRED_ARRAY:
case TYPE_FLEXIBLE_ARRAY:
asprintf(&buffer, "%s[*]", type_to_error_string(type->array.base));
return buffer;
case TYPE_SUBARRAY:
@@ -207,6 +209,8 @@ RETRY:
}
case CT_TYPES:
UNREACHABLE;
case TYPE_FLEXIBLE_ARRAY:
return 0;
case TYPE_FAILABLE:
type = type->failable;
goto RETRY;
@@ -315,6 +319,7 @@ bool type_is_abi_aggregate(Type *type)
case TYPE_TYPEINFO:
case TYPE_INFERRED_ARRAY:
case TYPE_UNTYPED_LIST:
case TYPE_FLEXIBLE_ARRAY:
UNREACHABLE
}
UNREACHABLE
@@ -446,6 +451,7 @@ AlignSize type_abi_alignment(Type *type)
return t.iptr.canonical->builtin.abi_alignment;
case TYPE_ARRAY:
case TYPE_INFERRED_ARRAY:
case TYPE_FLEXIBLE_ARRAY:
type = type->array.base;
goto RETRY;
case TYPE_SUBARRAY:
@@ -565,6 +571,33 @@ static Type *type_generate_inferred_array(Type *arr_type, bool canonical)
return arr;
}
static Type *type_generate_flexible_array(Type *arr_type, bool canonical)
{
if (canonical) arr_type = arr_type->canonical;
if (!arr_type->type_cache)
{
create_type_cache(arr_type);
}
Type *arr = arr_type->type_cache[FLEXIBLE_ARRAY_OFFSET];
if (arr == NULL)
{
arr = type_new(TYPE_FLEXIBLE_ARRAY, strformat("%s[*]", arr_type->name));
arr->array.base = arr_type;
arr->array.len = 0;
arr_type->type_cache[FLEXIBLE_ARRAY_OFFSET] = arr;
if (arr_type == arr_type->canonical)
{
arr->canonical = arr;
}
else
{
arr->canonical = type_generate_flexible_array(arr_type->canonical, true);
}
}
return arr;
}
Type *type_get_ptr_recurse(Type *ptr_type)
{
@@ -599,6 +632,11 @@ Type *type_get_inferred_array(Type *arr_type)
return type_generate_inferred_array(arr_type, false);
}
Type *type_get_flexible_array(Type *arr_type)
{
return type_generate_flexible_array(arr_type, false);
}
static inline bool array_structurally_equivalent_to_struct(Type *array, Type *type)
{
assert(array->type_kind == TYPE_ARRAY);
@@ -716,6 +754,7 @@ Type *type_get_indexed_type(Type *type)
case TYPE_ARRAY:
case TYPE_SUBARRAY:
case TYPE_INFERRED_ARRAY:
case TYPE_FLEXIBLE_ARRAY:
case TYPE_VECTOR:
return type->array.base;
case TYPE_DISTINCT:
@@ -895,6 +934,9 @@ static void type_append_name_to_scratch(Type *type)
case TYPE_SUBARRAY:
type_append_name_to_scratch(type->pointer);
scratch_buffer_append("[]");
case TYPE_FLEXIBLE_ARRAY:
type_append_name_to_scratch(type->pointer);
scratch_buffer_append("[*]");
case TYPE_VOID:
case TYPE_BOOL:
case TYPE_I8:
@@ -1078,6 +1120,7 @@ bool type_is_scalar(Type *type)
case TYPE_VECTOR:
case TYPE_FAILABLE_ANY:
case TYPE_ANY:
case TYPE_FLEXIBLE_ARRAY:
return false;
case TYPE_BOOL:
case ALL_INTS:
@@ -1355,6 +1398,7 @@ Type *type_find_max_type(Type *type, Type *other)
case TYPE_TYPEINFO:
case TYPE_ANY:
case TYPE_BITSTRUCT:
case TYPE_FLEXIBLE_ARRAY:
return NULL;
case ALL_INTS:
if (other->type_kind == TYPE_DISTINCT && type_underlying_is_numeric(other)) return other;

View File

@@ -11,12 +11,6 @@ struct Bar
{
int y;
}
struct
{}
union
{
struct { }
}
}
bitstruct : uint
{
@@ -68,20 +62,20 @@ entry:
%8 = ashr i32 %7, 23
call void (i8*, ...) @printf(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str, i32 0, i32 0), i32 %4, i32 %8)
%9 = bitcast %Foo* %f to i8*
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %9, i8* align 4 bitcast (%Foo* @.__const.8 to i8*), i32 16, i1 false)
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %9, i8* align 4 bitcast (%Foo* @.__const.5 to i8*), i32 16, i1 false)
%10 = getelementptr inbounds %Foo, %Foo* %f, i32 0, i32 0
%11 = getelementptr inbounds %anon.4, %anon.4* %10, i32 0, i32 0
%12 = getelementptr inbounds %anon.5, %anon.5* %11, i32 0, i32 0
%11 = getelementptr inbounds %anon.1, %anon.1* %10, i32 0, i32 0
%12 = getelementptr inbounds %anon.2, %anon.2* %11, i32 0, i32 0
%13 = load i32, i32* %12, align 4
%14 = getelementptr inbounds %Foo, %Foo* %f, i32 0, i32 0
%15 = getelementptr inbounds %anon.4, %anon.4* %14, i32 0, i32 1
%16 = getelementptr inbounds %anon.6, %anon.6* %15, i32 0, i32 0
%15 = getelementptr inbounds %anon.1, %anon.1* %14, i32 0, i32 1
%16 = getelementptr inbounds %anon.3, %anon.3* %15, i32 0, i32 0
%17 = load i32, i32* %16, align 4
%18 = getelementptr inbounds %Foo, %Foo* %f, i32 0, i32 0
%19 = getelementptr inbounds %anon.4, %anon.4* %18, i32 0, i32 2
%19 = getelementptr inbounds %anon.1, %anon.1* %18, i32 0, i32 2
%20 = load i32, i32* %19, align 4
%21 = getelementptr inbounds %Foo, %Foo* %f, i32 0, i32 1
%22 = load i32, i32* %21, align 4
call void (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.9, i32 0, i32 0), i32 %13, i32 %17, i32 %20, i32 %22)
call void (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.6, i32 0, i32 0), i32 %13, i32 %17, i32 %20, i32 %22)
ret void
}

View File

@@ -0,0 +1,7 @@
struct Foo // #error: Zero sized structs are not permitted.
{
}
union Bar // #error: Zero sized unions are not permitted.
{
}

View File

@@ -4,7 +4,9 @@ fn void test1()
}
struct Foo
{}
{
int x;
}
fn void test2()
{

View File

@@ -3,7 +3,7 @@ module mymodule;
extern fn void printf(char *, ...);
struct Foo { }
struct Foo { int y; }
int b;

View File

@@ -0,0 +1,3 @@
define Abc = int[*]; // #error: Inferred array types can only be used in declarations with initializers.
define Bcd = anyerr; // #error: 'anyerr' may not be aliased.
define Efd = variant; // #error: 'variant' may not be aliased.

View File

@@ -1,5 +1,5 @@
struct Foo
{}
{ int j; }
fn int main()
{

View File

@@ -1,6 +1,6 @@
define Callback = fn int(char c);
struct Person {}
struct Company {}
struct Person { int i; }
struct Company { int j; }
enum Status : int
{
IDLE,

View File

@@ -10,6 +10,7 @@ struct An3
struct An2
{
int z;
}
extern fn void printf(char *string);

View File

@@ -10,6 +10,7 @@ struct An3
struct An2
{
int y;
}
extern fn void printf(char* string);

View File

@@ -0,0 +1,31 @@
struct Foo
{
int x;
int[*] y; // #error: flexible array member must be the last element
int z;
}
struct Bar
{
int[*] y; // #error: flexible array member cannot be the only element
}
struct Baz
{
int y;
int[*] z;
}
struct BazContainerOk
{
int z;
Baz c;
}
struct BazContainer
{
Baz c; // #error: A struct member with a flexible array must be the last element.
int y;
}
Baz[5] ab; // #error: Arrays of structs with flexible array members is not allowed.

View File

@@ -0,0 +1,35 @@
// #target: x64-darwin
module foo;
struct Bar
{
struct
{
int y;
}
int ufe;
int[*] z;
}
fn void test(Bar b)
{
b.z[1];
}
/* #expect: foo.ll
%Bar = type { %anon, i32, [0 x i32] }
%anon = type { i32 }
define void @foo.test(%Bar* byval(%Bar) align 8 %0) #0 {
entry:
%b = alloca %Bar, align 4
%1 = bitcast %Bar* %b to i8*
%2 = bitcast %Bar* %0 to i8*
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %1, i8* align 8 %2, i32 8, i1 false)
%3 = getelementptr inbounds %Bar, %Bar* %b, i32 0, i32 2
%4 = getelementptr inbounds [0 x i32], [0 x i32]* %3, i64 0, i64 1
%5 = load i32, i32* %4, align 4
ret void
}

View File

@@ -0,0 +1,7 @@
define Foo = int[0];
struct Bar
{
Foo x; // #error: Zero length arrays are not valid members.
int b;
}

View File

@@ -0,0 +1,5 @@
union Zee
{
int z;
int[*] y; // #error: Flexible array members not allowed in unions.
}

View File

@@ -1,7 +1,5 @@
module test;
struct Empty {}
union Foo {}
union Qu
{
Qu *x;