diff --git a/releasenotes.md b/releasenotes.md index a6ea24d3f..56a679f01 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -18,6 +18,7 @@ - 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. - Array comparison now uses built-in memcmp on LLVM to enable optimizations. +- Prevent implicit array casts to pointers with higher alignment #1237. ### Fixes - Error with unsigned compare in `@ensure` when early returning 0 #1207. diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 3fcb8116e..e7768bf20 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -2496,6 +2496,7 @@ typedef enum TYPE_MISMATCH = 0, TYPE_SAME = 1, TYPE_SAME_INT_SIZE = 2, + TYPE_ALIGNMENT_INCREASE = 3, TYPE_ERROR = -1, } TypeCmpResult; diff --git a/src/compiler/sema_casts.c b/src/compiler/sema_casts.c index c7b64ac62..ea76d39be 100644 --- a/src/compiler/sema_casts.c +++ b/src/compiler/sema_casts.c @@ -682,6 +682,17 @@ static bool rule_ptr_to_ptr(CastContext *cc, bool is_explicit, bool is_silent) return true; case TYPE_ERROR: return false; + case TYPE_ALIGNMENT_INCREASE: + if (is_explicit) return false; + assert(!is_explicit); + RETURN_CAST_ERROR(cc->expr, + "Implicitly casting %s (alignment %d) to %s (alignment %d) is not permitted, " + "it would require an explicit cast. Before using an explicit cast, please make " + "sure you understand the ramifications as the explicit cast might crash your program if used incorrectly.", + type_quoted_error_string(type_no_optional(cc->expr->type)), + type_abi_alignment(type_get_indexed_type(cc->expr->type)), + type_quoted_error_string(cc->to), + type_abi_alignment(type_get_indexed_type(cc->to))); case TYPE_MISMATCH: case TYPE_SAME_INT_SIZE: return sema_cast_error(cc, true, is_silent); diff --git a/src/compiler/types.c b/src/compiler/types.c index 09e83324b..6b9d83890 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -1661,6 +1661,8 @@ RETRY: if (to_pointee->type_kind != from_pointee->type_kind) { + TypeCmpResult res_current = TYPE_SAME; + if (type_abi_alignment(to_pointee) > type_abi_alignment(from_pointee)) res_current = TYPE_ALIGNMENT_INCREASE; if (type_is_matching_int(to_pointee, from_pointee)) return TYPE_SAME_INT_SIZE; if (type_is_any_arraylike(from_pointee)) @@ -1669,10 +1671,11 @@ RETRY: if (type_is_any_arraylike(to_pointee)) { TypeCmpResult res = type_array_is_equivalent(context, to_pointee, from_pointee, flatten_distinct); - if (res != TYPE_MISMATCH) return res; + if (res != TYPE_MISMATCH) return res == TYPE_SAME ? res_current : res; } // A possible int[4]* -> int* decay? - return type_is_pointer_equivalent(context, type_get_ptr(from_pointee->array.base), to_pointer, flatten_distinct); + TypeCmpResult res = type_is_pointer_equivalent(context, type_get_ptr(from_pointee->array.base), to_pointer, flatten_distinct); + return res == TYPE_SAME ? res_current : res; } // Not arraylike and no array decay. Failure. return TYPE_MISMATCH; diff --git a/test/test_suite/expressions/casts/cast_vector_fail.c3 b/test/test_suite/expressions/casts/cast_vector_fail.c3 new file mode 100644 index 000000000..df92120ff --- /dev/null +++ b/test/test_suite/expressions/casts/cast_vector_fail.c3 @@ -0,0 +1,17 @@ +module foo; +import std; +fn void test(float[<4>]* x) +{} +fn void test2(float[4]* x) +{} + +fn int main(String[] args) +{ + float[4] a; + float[<4>] b; + test(&a); // #error: Implicitly casting + test(&b); + test2(&a); + test2(&b); + return 1; +}