diff --git a/resources/lib/std/runtime.c3 b/resources/lib/std/runtime.c3 index d8a053108..81ed609d4 100644 --- a/resources/lib/std/runtime.c3 +++ b/resources/lib/std/runtime.c3 @@ -26,7 +26,3 @@ struct VarArrayHeader } -struct VarArrayContainer -{ - -} diff --git a/src/compiler/codegen_general.c b/src/compiler/codegen_general.c index f1ee04af1..ee65e536f 100644 --- a/src/compiler/codegen_general.c +++ b/src/compiler/codegen_general.c @@ -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; diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 857dec0a7..eb29e6fde 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -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); diff --git a/src/compiler/enums.h b/src/compiler/enums.h index 86b80056f..a1fccfb11 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -554,6 +554,7 @@ typedef enum TYPE_ARRAY, TYPE_SUBARRAY, TYPE_INFERRED_ARRAY, + TYPE_FLEXIBLE_ARRAY, TYPE_UNTYPED_LIST, TYPE_FAILABLE, TYPE_FAILABLE_ANY, diff --git a/src/compiler/headers.c b/src/compiler/headers.c index fe192ec16..3c5b8281e 100644 --- a/src/compiler/headers.c +++ b/src/compiler/headers.c @@ -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: diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index 30c284a1e..00c69e918 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -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: { diff --git a/src/compiler/llvm_codegen_c_abi_x64.c b/src/compiler/llvm_codegen_c_abi_x64.c index c5066133e..3e4697daf 100644 --- a/src/compiler/llvm_codegen_c_abi_x64.c +++ b/src/compiler/llvm_codegen_c_abi_x64.c @@ -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; diff --git a/src/compiler/llvm_codegen_c_abi_x86.c b/src/compiler/llvm_codegen_c_abi_x86.c index b1f14a0ea..d335a0618 100644 --- a/src/compiler/llvm_codegen_c_abi_x86.c +++ b/src/compiler/llvm_codegen_c_abi_x86.c @@ -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: diff --git a/src/compiler/llvm_codegen_debug_info.c b/src/compiler/llvm_codegen_debug_info.c index 62649c1a5..4f404a77a 100644 --- a/src/compiler/llvm_codegen_debug_info.c +++ b/src/compiler/llvm_codegen_debug_info.c @@ -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); diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index d4ed6a435..ce287079c 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -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: diff --git a/src/compiler/llvm_codegen_type.c b/src/compiler/llvm_codegen_type.c index 327935c38..52627cf51 100644 --- a/src/compiler/llvm_codegen_type.c +++ b/src/compiler/llvm_codegen_type.c @@ -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: { diff --git a/src/compiler/sema_casts.c b/src/compiler/sema_casts.c index 8814b274e..dbb9cb925 100644 --- a/src/compiler/sema_casts.c +++ b/src/compiler/sema_casts.c @@ -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; diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index 205937398..f1538e997 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -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: diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index b6d6f9398..37f0659e9 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -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: diff --git a/src/compiler/sema_types.c b/src/compiler/sema_types.c index 674bbe1eb..ed42fb45e 100644 --- a/src/compiler/sema_types.c +++ b/src/compiler/sema_types.c @@ -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); diff --git a/src/compiler/types.c b/src/compiler/types.c index 2f0c545cd..f6db854b5 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -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; diff --git a/test/test_suite/bitstruct/embedded_bitstruct.c3t b/test/test_suite/bitstruct/embedded_bitstruct.c3t index 7cb21407b..59d7b3954 100644 --- a/test/test_suite/bitstruct/embedded_bitstruct.c3t +++ b/test/test_suite/bitstruct/embedded_bitstruct.c3t @@ -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 } diff --git a/test/test_suite/bitstruct/invalid_empty_struct_union.c3 b/test/test_suite/bitstruct/invalid_empty_struct_union.c3 new file mode 100644 index 000000000..d51661a07 --- /dev/null +++ b/test/test_suite/bitstruct/invalid_empty_struct_union.c3 @@ -0,0 +1,7 @@ +struct Foo // #error: Zero sized structs are not permitted. +{ +} + +union Bar // #error: Zero sized unions are not permitted. +{ +} \ No newline at end of file diff --git a/test/test_suite/compile_time_introspection/defined_err.c3 b/test/test_suite/compile_time_introspection/defined_err.c3 index 59f9e8aca..27d9bbf03 100644 --- a/test/test_suite/compile_time_introspection/defined_err.c3 +++ b/test/test_suite/compile_time_introspection/defined_err.c3 @@ -4,7 +4,9 @@ fn void test1() } struct Foo -{} +{ + int x; +} fn void test2() { diff --git a/test/test_suite/compile_time_introspection/nameof.c3t b/test/test_suite/compile_time_introspection/nameof.c3t index 0d9656cb4..f795a2b83 100644 --- a/test/test_suite/compile_time_introspection/nameof.c3t +++ b/test/test_suite/compile_time_introspection/nameof.c3t @@ -3,7 +3,7 @@ module mymodule; extern fn void printf(char *, ...); -struct Foo { } +struct Foo { int y; } int b; diff --git a/test/test_suite/define/forbidden_defines.c3 b/test/test_suite/define/forbidden_defines.c3 new file mode 100644 index 000000000..78fc1ce82 --- /dev/null +++ b/test/test_suite/define/forbidden_defines.c3 @@ -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. diff --git a/test/test_suite/expressions/no_valid_conversion_minus.c3 b/test/test_suite/expressions/no_valid_conversion_minus.c3 index 30c91a85a..68ad6a1c1 100644 --- a/test/test_suite/expressions/no_valid_conversion_minus.c3 +++ b/test/test_suite/expressions/no_valid_conversion_minus.c3 @@ -1,5 +1,5 @@ struct Foo -{} +{ int j; } fn int main() { diff --git a/test/test_suite/from_docs/examples_struct.c3 b/test/test_suite/from_docs/examples_struct.c3 index 065e4de8c..dccc7d404 100644 --- a/test/test_suite/from_docs/examples_struct.c3 +++ b/test/test_suite/from_docs/examples_struct.c3 @@ -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, diff --git a/test/test_suite/macro_methods/access.c3 b/test/test_suite/macro_methods/access.c3 index cc29bc6b7..07f22dc87 100644 --- a/test/test_suite/macro_methods/access.c3 +++ b/test/test_suite/macro_methods/access.c3 @@ -10,6 +10,7 @@ struct An3 struct An2 { + int z; } extern fn void printf(char *string); diff --git a/test/test_suite/macro_methods/macro_method_fails.c3 b/test/test_suite/macro_methods/macro_method_fails.c3 index 697a570e6..d1f10338a 100644 --- a/test/test_suite/macro_methods/macro_method_fails.c3 +++ b/test/test_suite/macro_methods/macro_method_fails.c3 @@ -10,6 +10,7 @@ struct An3 struct An2 { + int y; } extern fn void printf(char* string); diff --git a/test/test_suite/struct/flex_array_struct_err.c3 b/test/test_suite/struct/flex_array_struct_err.c3 new file mode 100644 index 000000000..59faccf3b --- /dev/null +++ b/test/test_suite/struct/flex_array_struct_err.c3 @@ -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. \ No newline at end of file diff --git a/test/test_suite/struct/struct_codegen_fam.c3t b/test/test_suite/struct/struct_codegen_fam.c3t new file mode 100644 index 000000000..6ab354811 --- /dev/null +++ b/test/test_suite/struct/struct_codegen_fam.c3t @@ -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 +} \ No newline at end of file diff --git a/test/test_suite/struct/zero_member.c3 b/test/test_suite/struct/zero_member.c3 new file mode 100644 index 000000000..fb5c145ad --- /dev/null +++ b/test/test_suite/struct/zero_member.c3 @@ -0,0 +1,7 @@ +define Foo = int[0]; + +struct Bar +{ + Foo x; // #error: Zero length arrays are not valid members. + int b; +} \ No newline at end of file diff --git a/test/test_suite/union/flexible_array_union.c3 b/test/test_suite/union/flexible_array_union.c3 new file mode 100644 index 000000000..42bbe8276 --- /dev/null +++ b/test/test_suite/union/flexible_array_union.c3 @@ -0,0 +1,5 @@ +union Zee +{ + int z; + int[*] y; // #error: Flexible array members not allowed in unions. +} \ No newline at end of file diff --git a/test/test_suite/union/empty_unions.c3 b/test/test_suite/union/test_unions.c3 similarity index 89% rename from test/test_suite/union/empty_unions.c3 rename to test/test_suite/union/test_unions.c3 index a22d5734d..8f465442b 100644 --- a/test/test_suite/union/empty_unions.c3 +++ b/test/test_suite/union/test_unions.c3 @@ -1,7 +1,5 @@ module test; -struct Empty {} -union Foo {} union Qu { Qu *x;