diff --git a/src/compiler/sema_casts.c b/src/compiler/sema_casts.c index 15ab6e7a8..9900a1dbc 100644 --- a/src/compiler/sema_casts.c +++ b/src/compiler/sema_casts.c @@ -237,6 +237,7 @@ static bool voidfail_to_error(Expr *expr, Type *type) return true; } + /** * Cast int to bool using CAST_INTBOOL * or rewrite 0 => false, any other value => true @@ -466,18 +467,56 @@ static bool array_to_vector(Expr *expr, Type *to_type) /** * We have two cases: * 1. int[] -> Foo[] where Foo is a distinct or typedef OR it is a constant. Then we can just redefine - * 2. The second case is something like int*[] -> void*[] for this case we need to make a bitcast. + * 2. The second case is something like int*[] -> void*[] for this case we need to make a bitcast using CAST_SASA. */ INLINE bool subarray_to_subarray(Expr *expr, Type *to_type) { if (expr_is_const(expr) || type_flatten(type_flatten(to_type)->array.base) == type_flatten(type_flatten(expr->type)->array.base)) { + // Here we assume int[] -> float[] can't happen. expr->type = to_type; return true; } return insert_cast(expr, CAST_SASA, to_type); } +/** + * Bitstruct casts go from its base type to any integer or char array of the same size. + */ +static bool bitstruct_cast(Expr *expr, Type *bitstruct_type, Type *to, Type *to_type) +{ + assert(type_size(to) == type_size(bitstruct_type) && "Only casts to the same width expected."); + + // The case where the bitstruct is backed by an integer + if (type_is_integer(bitstruct_type)) + { + // The same size integer, this is the simple case. + if (type_is_integer(to)) + { + expr->type = to_type; + return true; + } + // Now we expect a char array of the same size. This + // is runtime only. + assert(to->type_kind == TYPE_ARRAY); + return insert_cast(expr, CAST_BSARRY, to_type); + } + + // Converting from a char array. + assert(bitstruct_type->type_kind == TYPE_ARRAY); + + // Converting to a char array is the simple case, just change the type. + if (to->type_kind == TYPE_ARRAY) + { + expr->type = to_type; + return true; + } + + // Converting to an integer, this is a runtime cast. + assert(type_is_integer(to)); + return insert_cast(expr, CAST_BSINT, to_type); +} + /** * Cast using CAST_VECARR, casting an array to a vector. For the constant, this * is a simple type change, see array_to_vector. @@ -568,6 +607,39 @@ bool cast_promote_vararg(Expr *arg) return true; } +/** + * Given lhs and rhs, promote to the maximum bit size, this will retain + * signed/unsigned type of each side. + */ +void cast_to_int_to_max_bit_size(SemaContext *context, Expr *lhs, Expr *rhs, Type *left_type, Type *right_type) +{ + unsigned bit_size_left = left_type->builtin.bitsize; + unsigned bit_size_right = right_type->builtin.bitsize; + + assert(bit_size_left && bit_size_right); + + // Simple case they are the same size, just return. + if (bit_size_left == bit_size_right) return; + + // Lhs is smaller than rhs, so widen it using the right type + if (bit_size_left < bit_size_right) + { + Type *to = lhs->type->type_kind < TYPE_U8 + ? type_int_signed_by_bitsize(bit_size_right) + : type_int_unsigned_by_bitsize(bit_size_right); + bool success = cast(lhs, to); + assert(success); + return; + } + + // Rhs is smaller, do the same thing as above but with the rhs. + Type *to = rhs->type->type_kind < TYPE_U8 + ? type_int_signed_by_bitsize(bit_size_left) + : type_int_unsigned_by_bitsize(bit_size_left); + bool success = cast(rhs, to); + assert(success); +} + /** * For implicit casts to bool, in a conditional, return the type of cast to * insert. @@ -1931,7 +2003,7 @@ static bool cast_inner(Expr *expr, Type *from_type, Type *to, Type *to_type) case CT_TYPES: UNREACHABLE case TYPE_BITSTRUCT: - return bitstruct_cast(expr, from_type, to, to_type); + return bitstruct_cast(expr, type_flatten(from_type->decl->bitstruct.base_type->type), to, to_type); case TYPE_BOOL: // Bool may convert into integers and floats but only explicitly. if (type_is_integer(to)) return bool_to_int(expr, to, to_type); @@ -2019,28 +2091,6 @@ static bool cast_inner(Expr *expr, Type *from_type, Type *to, Type *to_type) UNREACHABLE } -static bool bitstruct_cast(Expr *expr, Type *from_type, Type *to, Type *to_type) -{ - Type *base_type = type_flatten_distinct(from_type->decl->bitstruct.base_type->type); - assert(type_size(to) == type_size(base_type)); - if (type_is_integer(base_type) && type_is_integer(to)) - { - expr->type = to_type; - return true; - } - if (base_type->type_kind == TYPE_ARRAY && to->type_kind == TYPE_ARRAY) - { - expr->type = to_type; - return true; - } - if (type_is_integer(base_type)) - { - assert(to->type_kind == TYPE_ARRAY); - return insert_cast(expr, CAST_BSARRY, to_type); - } - assert(base_type->type_kind == TYPE_ARRAY); - return insert_cast(expr, CAST_BSINT, to_type); -} bool cast(Expr *expr, Type *to_type) { @@ -2173,37 +2223,7 @@ Type *cast_numeric_arithmetic_promotion(Type *type) } } -bool cast_decay_array_pointers(SemaContext *context, Expr *expr) -{ - CanonicalType *pointer_type = type_pointer_type(type_no_optional(expr->type)); - if (!pointer_type || !type_is_arraylike(pointer_type)) return true; - return cast_expr_inner(context, - expr, - type_add_optional(type_get_ptr(pointer_type->array.base), IS_OPTIONAL(expr)), - true, false, false); -} -void cast_to_max_bit_size(SemaContext *context, Expr *left, Expr *right, Type *left_type, Type *right_type) -{ - unsigned bit_size_left = left_type->builtin.bitsize; - unsigned bit_size_right = right_type->builtin.bitsize; - assert(bit_size_left && bit_size_right); - if (bit_size_left == bit_size_right) return; - if (bit_size_left < bit_size_right) - { - Type *to = left->type->type_kind < TYPE_U8 - ? type_int_signed_by_bitsize(bit_size_right) - : type_int_unsigned_by_bitsize(bit_size_right); - bool success = cast(left, to); - assert(success); - return; - } - Type *to = right->type->type_kind < TYPE_U8 - ? type_int_signed_by_bitsize(bit_size_left) - : type_int_unsigned_by_bitsize(bit_size_left); - bool success = cast(right, to); - assert(success); -} #pragma clang diagnostic pop \ No newline at end of file diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 2945eb50c..fbe06f986 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -4324,7 +4324,6 @@ static bool sema_expr_analyse_add_sub_assign(SemaContext *context, Expr *expr, E if (left_type_canonical->type_kind == TYPE_POINTER) { - if (!cast_decay_array_pointers(context, left)) return false; expr->type = left->type; // 7. Finally, check that the right side is indeed an integer. @@ -4423,13 +4422,11 @@ static bool sema_expr_analyse_sub(SemaContext *context, Expr *expr, Expr *left, // 2. Handle the ptr - x and ptr - other_pointer if (left_type->type_kind == TYPE_POINTER) { - if (!cast_decay_array_pointers(context, left)) return false; left_type = type_no_optional(left->type)->canonical; // 3. ptr - other pointer if (right_type->type_kind == TYPE_POINTER) { - if (!cast_decay_array_pointers(context, right)) return false; right_type = type_no_optional(right->type)->canonical; // 3a. Require that both types are the same. @@ -4580,8 +4577,6 @@ static bool sema_expr_analyse_add(SemaContext *context, Expr *expr, Expr *left, // so check if we want to do the normal pointer add special handling. if (left_type->type_kind == TYPE_POINTER) { - if (!cast_decay_array_pointers(context, left)) return false; - // 3a. Check that the other side is an integer of some sort. if (!type_is_integer(right_type)) { @@ -5076,7 +5071,7 @@ static bool sema_expr_analyse_comp(SemaContext *context, Expr *expr, Expr *left, || (type_is_signed(left_type) && type_is_unsigned(right_type))) { // 2a. Resize so that both sides have the same bit width. This will always work. - cast_to_max_bit_size(context, left, right, left_type, right_type); + cast_to_int_to_max_bit_size(context, left, right, left_type, right_type); goto DONE; } @@ -5580,8 +5575,6 @@ static inline bool sema_expr_analyse_incdec(SemaContext *context, Expr *expr) return false; } - if (!cast_decay_array_pointers(context, inner)) return false; - // 6. Done, the result is same as the inner type. expr->type = inner->type; return true; diff --git a/src/compiler/sema_internal.h b/src/compiler/sema_internal.h index 2ad8f319f..c4c233122 100644 --- a/src/compiler/sema_internal.h +++ b/src/compiler/sema_internal.h @@ -83,8 +83,8 @@ Type *sema_analyse_function_signature(SemaContext *context, Decl *parent, CallAB bool cast_widen_top_down(SemaContext *context, Expr *expr, Type *type); bool cast_promote_vararg(Expr *arg); Type *cast_numeric_arithmetic_promotion(Type *type); -void cast_to_max_bit_size(SemaContext *context, Expr *left, Expr *right, Type *left_type, Type *right_type); -bool cast_decay_array_pointers(SemaContext *context, Expr *expr); +void cast_to_int_to_max_bit_size(SemaContext *context, Expr *lhs, Expr *rhs, Type *left_type, Type *right_type); + INLINE bool sema_set_abi_alignment(SemaContext *context, Type *type, AlignSize *result); INLINE bool sema_set_alloca_alignment(SemaContext *context, Type *type, AlignSize *result); void sema_display_deprecated_warning_on_use(SemaContext *context, Decl *decl, SourceSpan use); diff --git a/src/version.h b/src/version.h index 72e0bbbd3..ddd7f0d71 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "0.4.92" \ No newline at end of file +#define COMPILER_VERSION "0.4.93" \ No newline at end of file diff --git a/test/test_suite/bitstruct/bitstruct_cast_const_init.c3t b/test/test_suite/bitstruct/bitstruct_cast_const_init.c3t new file mode 100644 index 000000000..6a1f822cd --- /dev/null +++ b/test/test_suite/bitstruct/bitstruct_cast_const_init.c3t @@ -0,0 +1,20 @@ +// #target: macos-x64 +module test; +bitstruct Foo : int +{ + int abc : 0..4; + int def : 23..26; +} + +fn void main() +{ + Foo f; + int z = (int) Foo { .abc = 2, .def = 1 }; +} + +/* #expect: test.ll + + %f = alloca i32, align 4 + %z = alloca i32, align 4 + store i32 0, ptr %f, align 4 + store i32 8388610, ptr %z, align 4 \ No newline at end of file diff --git a/test/test_suite/pointers/array_pointer_decay.c3t b/test/test_suite/pointers/array_pointer_decay.c3t index b7c1840a4..e3f8dea4c 100644 --- a/test/test_suite/pointers/array_pointer_decay.c3t +++ b/test/test_suite/pointers/array_pointer_decay.c3t @@ -13,7 +13,7 @@ fn void main() int* xx = &x + 1; int[3]* yy = (int[3]*)(xx); int* zz = yy - 1; - printf("%p = %p = %p, %p = %p\n", y, z, zz, &(*y)[1], xx); + printf("%p = %p = %p, %p != %p\n", y, z, zz, &(*y)[1], xx); x[1] = 123; printf("%d = %d\n", x[1], z[1]); } @@ -52,12 +52,12 @@ entry: %ptroffset1 = getelementptr inbounds i32, ptr %8, i64 1 %9 = load i32, ptr %ptroffset1, align 4 store i32 %9, ptr %z1, align 4 - %ptroffset2 = getelementptr i32, ptr %x, i64 1 + %ptroffset2 = getelementptr [3 x i32], ptr %x, i64 1 store ptr %ptroffset2, ptr %xx, align 8 %10 = load ptr, ptr %xx, align 8 store ptr %10, ptr %yy, align 8 %11 = load ptr, ptr %yy, align 8 - %ptroffset3 = getelementptr i32, ptr %11, i64 -1 + %ptroffset3 = getelementptr [3 x i32], ptr %11, i64 -1 store ptr %ptroffset3, ptr %zz, align 8 %12 = load ptr, ptr %y, align 8 %13 = load ptr, ptr %z, align 8 diff --git a/test/unit/regression/pointer_non_decay.c3 b/test/unit/regression/pointer_non_decay.c3 new file mode 100644 index 000000000..2834f7513 --- /dev/null +++ b/test/unit/regression/pointer_non_decay.c3 @@ -0,0 +1,19 @@ +module test @test; + +fn void pointer_non_decay() +{ + int[3] x; + int[3]* y = &x; + int* z = y; + int[] sub = y; + int[3] y1 = y[1]; + int z1 = z[1]; + int* xx = &x + 1; + int[3]* yy = (int[3]*)(xx); + int* zz = yy - 1; + assert(y == z); + assert(z == zz); + assert(&(*y)[1] == &xx[-2]); + x[1] = 123; + assert(x[1] == z[1]); +} \ No newline at end of file