diff --git a/releasenotes.md b/releasenotes.md index 594681cd4..306486dfd 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -15,6 +15,8 @@ - `--no-headers` option to suppress creating headers when generating a library. - Support c-file compilation in libraries. - Allow using $defined(&a[1]) to check if the operation is supported. +- Max number of members in a struct is limited to 65535. +- The maximum number of parameters in a call is now 255, up from 127. ### Fixes - Error with unsigned compare in `@ensure` when early returning 0 #1207. @@ -35,6 +37,7 @@ - Fix ABI lowering for 128 bit vectors on Linux. - Bad error message when using a generic method without generic parameters #1228 - Private function called from nested macro not visible to linker #1232 +- Bitstructs in structs would not be correctly be handled in some cases. ### Stdlib changes - Added `remove_first_item` `remove_last_item` and `remove_item` as aliases for the `match` functions. diff --git a/src/compiler/copying.c b/src/compiler/copying.c index a504bc039..5673bbd0e 100644 --- a/src/compiler/copying.c +++ b/src/compiler/copying.c @@ -907,6 +907,7 @@ Decl *copy_decl(CopyStruct *c, Decl *decl) copy_decl_type(copy); MACRO_COPY_TYPE_LIST(copy->interfaces); MACRO_COPY_DECL_LIST(copy->strukt.members); + MACRO_COPY_DECLID(copy->strukt.padded_decl_id); MACRO_COPY_DECL_LIST(copy->methods); break; case DECL_DECLARRAY: diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index 291dc5d88..e28ae88d0 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -271,8 +271,7 @@ LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_ LLVMTypeRef element_type_llvm = llvm_get_type(c, element_type); AlignSize expected_align = llvm_abi_alignment(c, element_type_llvm); ConstInitializer **elements = const_init->init_array.elements; - unsigned element_count = vec_size(elements); - assert(element_count > 0 && "Array should always have gotten at least one element."); + assert(vec_size(elements) > 0 && "Array should always have gotten at least one element."); ArrayIndex current_index = 0; unsigned alignment = 0; LLVMValueRef *parts = NULL; diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index 6b3f9c660..ecdc217f9 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -804,14 +804,16 @@ static void llvm_emit_member_addr(GenContext *c, BEValue *value, Decl *parent, D } while (found != member); } -static void llvm_emit_bitstruct_member(GenContext *c, BEValue *value, Decl *parent, Decl *member) +static Decl *llvm_emit_bitstruct_member(GenContext *c, BEValue *value, Decl *parent, Decl *member) { assert(member->resolve_status == RESOLVE_DONE); - Decl *found = NULL; + Decl *found = parent; + Decl *last = NULL; do { ArrayIndex index = find_member_index(parent, member); assert(index > -1); + last = found; found = parent->strukt.members[index]; switch (parent->type->canonical->type_kind) { @@ -829,6 +831,7 @@ static void llvm_emit_bitstruct_member(GenContext *c, BEValue *value, Decl *pare } parent = found; } while (found != member); + return last ? last : parent; } static LLVMValueRef llvm_emit_bswap(GenContext *c, LLVMValueRef value) @@ -838,6 +841,7 @@ static LLVMValueRef llvm_emit_bswap(GenContext *c, LLVMValueRef value) return LLVMConstBswap(value); } LLVMTypeRef type = LLVMTypeOf(value); + assert(type != c->byte_type); return llvm_emit_call_intrinsic(c, intrinsic_id.bswap, &type, 1, &value, 1); } @@ -871,6 +875,7 @@ static inline void llvm_extract_bool_bit_from_array(GenContext *c, BEValue *be_v static inline LLVMValueRef llvm_bswap_non_integral(GenContext *c, LLVMValueRef value, unsigned bitsize) { if (bitsize <= 8) return value; + assert(is_power_of_two(bitsize)); LLVMValueRef shifted = llvm_emit_shl_fixed(c, value, (int)llvm_bitsize(c, LLVMTypeOf(value)) - (int)bitsize); return llvm_emit_bswap(c, shifted); } @@ -942,9 +947,8 @@ static inline void llvm_extract_bitvalue_from_array(GenContext *c, BEValue *be_v } -static inline void llvm_extract_bitvalue(GenContext *c, BEValue *be_value, Expr *parent, Decl *member) +static inline void llvm_extract_bitvalue(GenContext *c, BEValue *be_value, Decl *parent_decl, Decl *member) { - Decl *parent_decl = type_flatten(parent->type)->decl; if (be_value->type->type_kind == TYPE_ARRAY) { llvm_extract_bitvalue_from_array(c, be_value, member, parent_decl); @@ -1126,14 +1130,14 @@ static inline void llvm_emit_bitassign_expr(GenContext *c, BEValue *be_value, Ex BEValue parent; Decl *member = lhs->access_expr.ref; llvm_emit_expr(c, &parent, parent_expr); - llvm_emit_bitstruct_member(c, &parent, type_flatten(parent_expr->type)->decl, member); + Decl *parent_decl = llvm_emit_bitstruct_member(c, &parent, type_flatten(parent_expr->type)->decl, member); // If we have assign + op, load the current value, perform the operation. if (expr->binary_expr.operator != BINARYOP_ASSIGN) { // Grab the current value. BEValue value = parent; - llvm_extract_bitvalue(c, &value, parent_expr, member); + llvm_extract_bitvalue(c, &value, parent_decl, member); // Perform the operation and place it in be_value llvm_emit_binary(c, be_value, expr, &value, binaryop_assign_base_op(expr->binary_expr.operator)); } @@ -1152,10 +1156,10 @@ static inline void llvm_emit_bitassign_expr(GenContext *c, BEValue *be_value, Ex // To start the assign, pull out the current value. LLVMValueRef current_value = llvm_load_value_store(c, &parent); - bool bswap = bitstruct_requires_bitswap(parent_type->decl); + bool bswap = bitstruct_requires_bitswap(parent_decl); if (bswap) current_value = llvm_emit_bswap(c, current_value); LLVMValueRef value = llvm_load_value_store(c, be_value); - current_value = llvm_emit_bitstruct_value_update(c, current_value, type_size(parent.type) * 8, LLVMTypeOf(current_value), member, value); + current_value = llvm_emit_bitstruct_value_update(c, current_value, type_size(parent_decl->type) * 8, LLVMTypeOf(current_value), member, value); if (bswap) current_value = llvm_emit_bswap(c, current_value); llvm_store_raw(c, &parent, current_value); } @@ -1167,8 +1171,8 @@ static inline void llvm_emit_bitaccess(GenContext *c, BEValue *be_value, Expr *e Decl *member = expr->access_expr.ref; assert(be_value && be_value->type); - llvm_emit_bitstruct_member(c, be_value, type_flatten(parent->type)->decl, member); - llvm_extract_bitvalue(c, be_value, parent, expr->access_expr.ref); + Decl *parent_decl = llvm_emit_bitstruct_member(c, be_value, type_flatten(parent->type)->decl, member); + llvm_extract_bitvalue(c, be_value, parent_decl, expr->access_expr.ref); } static inline void llvm_emit_access_addr(GenContext *c, BEValue *be_value, Expr *expr) @@ -2037,7 +2041,7 @@ static void llvm_emit_initialize_designated_element(GenContext *c, BEValue *ref, llvm_emit_expr(c, &exprval, expr); LLVMValueRef val = llvm_load_value_store(c, &exprval); LLVMTypeRef bitstruct_type = llvm_get_type(c, underlying_type); - bool is_bitswap = bitstruct_requires_bitswap(decl); + bool is_bitswap = bitstruct_requires_bitswap(type->decl); if (underlying_type->type_kind == TYPE_ARRAY) { llvm_emit_update_bitstruct_array(c, value.value, value.alignment, bitstruct_type, is_bitswap, member, val); @@ -2150,6 +2154,7 @@ static inline void llvm_emit_initialize_reference_designated(GenContext *c, BEVa static bool bitstruct_requires_bitswap(Decl *decl) { + assert(decl->decl_kind == DECL_BITSTRUCT); bool big_endian = platform_target.big_endian; if (decl->bitstruct.big_endian) return !big_endian; if (decl->bitstruct.little_endian) return big_endian; @@ -2435,27 +2440,26 @@ static inline void llvm_emit_pre_post_inc_dec_bitstruct(GenContext *c, BEValue * BEValue parent; Decl *member = lhs->access_expr.ref; llvm_emit_expr(c, &parent, parent_expr); - llvm_emit_bitstruct_member(c, &parent, type_flatten(parent_expr->type)->decl, member); + Decl *parent_decl = llvm_emit_bitstruct_member(c, &parent, type_flatten(parent_expr->type)->decl, member); BEValue value = parent; - llvm_extract_bitvalue(c, &value, parent_expr, member); + llvm_extract_bitvalue(c, &value, parent_decl, member); LLVMValueRef value_start = llvm_load_value_store(c, &value); LLVMValueRef result = llvm_emit_add_int(c, value.type, value_start, llvm_const_int(c, value.type, diff), lhs->span); llvm_value_set(be_value, pre ? result : value_start, value.type); - Type *parent_type = type_flatten(parent_expr->type); - if (type_lowering(parent_type)->type_kind == TYPE_ARRAY) + if (type_lowering(parent_decl->type)->type_kind == TYPE_ARRAY) { - llvm_emit_bitassign_array(c, result, parent, parent_type->decl, member); + llvm_emit_bitassign_array(c, result, parent, parent_decl, member); return; } // To start the assign, pull out the current value. LLVMValueRef current_value = llvm_load_value_store(c, &parent); - bool bswap = bitstruct_requires_bitswap(parent_type->decl); + bool bswap = bitstruct_requires_bitswap(parent_decl); if (bswap) current_value = llvm_emit_bswap(c, current_value); - current_value = llvm_emit_bitstruct_value_update(c, current_value, type_size(parent.type) * 8, LLVMTypeOf(current_value), member, result); + current_value = llvm_emit_bitstruct_value_update(c, current_value, type_size(parent_decl->type) * 8, LLVMTypeOf(current_value), member, result); if (bswap) current_value = llvm_emit_bswap(c, current_value); llvm_store_raw(c, &parent, current_value); } diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index 876e6e619..3bcfa12e7 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -276,7 +276,8 @@ static inline bool sema_analyse_struct_member(SemaContext *context, Decl *parent static inline bool sema_check_struct_holes(SemaContext *context, Decl *decl, Decl *member, Type *member_type) { member_type = type_flatten(member_type); - if (member_type->type_kind != TYPE_STRUCT && member_type->type_kind != TYPE_UNION) return true; + if (!type_is_union_or_strukt(member_type)) return true; + assert(decl_is_struct_type(member_type->decl)); if (!member_type->decl->strukt.padded_decl_id) return true; if (!decl->strukt.padded_decl_id) decl->strukt.padded_decl_id = member_type->decl->strukt.padded_decl_id; if (decl->attr_compact) @@ -377,6 +378,7 @@ static bool sema_analyse_union_members(SemaContext *context, Decl *decl) decl->is_packed = decl->is_packed && max_alignment > 1; // "Representative" type is the one with the maximum alignment. + assert(max_alignment_element >= 0); decl->strukt.union_rep = max_alignment_element; // All members share the same alignment @@ -590,6 +592,7 @@ static bool sema_analyse_struct_members(SemaContext *context, Decl *decl) if (align_offset - offset != 0) { + assert(decl_is_struct_type(decl)); if (!decl->strukt.padded_decl_id) decl->strukt.padded_decl_id = declid(member); if (decl->attr_nopadding || member->attr_nopadding) { @@ -647,6 +650,7 @@ static bool sema_analyse_struct_members(SemaContext *context, Decl *decl) if (size != offset) { + assert(decl_is_struct_type(decl)); if (!decl->strukt.padded_decl_id) decl->strukt.padded_decl_id = declid(decl); if (decl->attr_nopadding) { diff --git a/src/compiler/types.c b/src/compiler/types.c index e81ffb78f..09e83324b 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -1013,7 +1013,7 @@ static inline bool array_structurally_equivalent_to_struct(Type *array, Type *ty Decl **members = type->decl->strukt.members; // For structs / errors, all members must match. - ArrayIndex offset = 0; + ArrayIndex offset = 0; AlignSize align_size = type_abi_alignment(array); Type *array_base = array->array.base; FOREACH(Decl *, member, members) diff --git a/test/test_suite/functions/too_many_params.c3 b/test/test_suite/functions/too_many_params.c3 index c0a6917cf..5b7a190ca 100644 --- a/test/test_suite/functions/too_many_params.c3 +++ b/test/test_suite/functions/too_many_params.c3 @@ -7,11 +7,16 @@ fn int test1( int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // 100 - int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // - int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // #error: The number of params exceeded the max of 127. To accept more arguments, consider using varargs + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // 120 int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // - int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int // 200 + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // 200 + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // 220 + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // 240 + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // #error: The number of params exceeded + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int // 300 ) { return 1; } fn int test2( @@ -20,11 +25,16 @@ fn int test2( int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // 100 + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // 120 int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // - int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // #error: The number of params exceeded the max of 127. int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // 200 + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // 220 + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // 240 + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // #error: The number of params exceeded + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // + int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // 300 int... x ) { return 1; }