From 3400dd5e420a6846e67b251bd106eb33a1dcbcc2 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Wed, 23 Jul 2025 16:10:31 +0200 Subject: [PATCH] `char[*] b = *(char[*]*)&a;` would crash the compiler if `a` was a slice. #2320 --- releasenotes.md | 1 + src/compiler/sema_casts.c | 10 ++++++++-- test/test_suite/cast/cast_infer_slice.c3 | 7 +++++++ 3 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 test/test_suite/cast/cast_infer_slice.c3 diff --git a/releasenotes.md b/releasenotes.md index 3a3605a39..8601c5bd5 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -72,6 +72,7 @@ - Overloading addition with a pointer would not work. - Copying const enums and regular enums incorrect #2313. - Regression: Chaining an optional together with contracts could in some cases lose the optional. +- `char[*] b = *(char[*]*)&a;` would crash the compiler if `a` was a slice. #2320 ### Stdlib changes - Improve contract for readline. #2280 diff --git a/src/compiler/sema_casts.c b/src/compiler/sema_casts.c index 6cc67503b..80a0e2030 100644 --- a/src/compiler/sema_casts.c +++ b/src/compiler/sema_casts.c @@ -316,10 +316,10 @@ Type *type_infer_len_from_actual_type(Type *to_infer, Type *actual_type) // The case of int[*][2] x = ... return type_add_optional(type_get_array(indexed, to_infer->array.len), is_optional); case TYPE_INFERRED_ARRAY: - ASSERT(type_is_arraylike(type_flatten(actual_type))); + if (!type_is_arraylike(type_flatten(actual_type))) return to_infer; return type_add_optional(type_get_array(indexed, type_flatten(actual_type)->array.len), is_optional); case TYPE_INFERRED_VECTOR: - ASSERT(type_is_arraylike(type_flatten(actual_type))); + if (!type_is_arraylike(type_flatten(actual_type))) return to_infer; return type_add_optional(type_get_vector(indexed, type_flatten(actual_type)->array.len), is_optional); case TYPE_SLICE: return type_add_optional(type_get_slice(indexed), is_optional); @@ -1249,6 +1249,12 @@ static bool rule_ptr_to_infer(CastContext *cc, bool is_explicit, bool is_silent) if (cc->to->type_kind != TYPE_POINTER) return sema_cast_error(cc, false, is_silent); Type *new_type = type_infer_len_from_actual_type(cc->to, cc->from); + + if (type_to_group(new_type) == CONV_INFERRED) + { + if (is_silent) return false; + RETURN_CAST_ERROR(cc->expr, "This expression, of type %s, cannot be used to infer the length of %s.", type_quoted_error_string(cc->from), type_quoted_error_string(cc->to)); + } cast_context_set_to(cc, new_type->pointer->canonical); cast_context_set_from(cc, cc->from->pointer); return cast_is_allowed(cc, is_explicit, is_silent); diff --git a/test/test_suite/cast/cast_infer_slice.c3 b/test/test_suite/cast/cast_infer_slice.c3 new file mode 100644 index 000000000..480be6972 --- /dev/null +++ b/test/test_suite/cast/cast_infer_slice.c3 @@ -0,0 +1,7 @@ +import std; +fn int main() +{ + char[] a = "hello"; + char[*] b = *(char[*]*)&a; // #error: cannot be used to infer the length + return 0; +} \ No newline at end of file