Tighten up conversion rules for arrays and slices.

This commit is contained in:
Christoffer Lerno
2024-11-10 01:16:01 +01:00
parent 69004943a7
commit 547f2ef189
2 changed files with 21 additions and 34 deletions

View File

@@ -949,53 +949,34 @@ static bool rule_slice_to_slice(CastContext *cc, bool is_explicit, bool is_silen
Type *from_base = from_type->array.base;
Type *array_base = cc->to->array.base;
if (is_explicit)
{
array_base = type_flatten(array_base);
from_base = type_flatten(from_base);
}
// Same base type? Ok
if (from_base == array_base) return true;
if (from_base->canonical == array_base->canonical) return true;
// This is allowed: void*[] -> int*[] and int*[] -> void*[]
if ((from_base == type_voidptr && type_is_pointer_type(array_base)) || (array_base == type_voidptr && type_is_pointer_type(from_base))) return true;
if (is_silent) return false;
// Allow converting to any type with the same size (and a smaller or same alignment)
if (type_size(array_base) != type_size(from_base))
switch (type_array_element_is_equivalent(cc->context, array_base, from_base, is_explicit))
{
if (!is_explicit) return sema_cast_error(cc, false, is_silent);
if (is_silent) return false;
RETURN_CAST_ERROR(cc->expr, "%s cannot be cast to %s as its elements have different size.",
type_quoted_error_string(cc->expr->type), type_quoted_error_string(cc->to_type));
case TYPE_ERROR:
return false;
case TYPE_MISMATCH:
case TYPE_ALIGNMENT_INCREASE:
if (is_silent) return false;
return sema_cast_error(cc, is_explicit ? false : rule_slice_to_slice(cc, true, true), is_silent);
case TYPE_SAME:
case TYPE_SAME_INT_SIZE:
return true;
}
if (type_abi_alignment(from_base) < type_abi_alignment(array_base))
{
if (!is_explicit) return sema_cast_error(cc, false, is_silent);
if (is_silent) return false;
RETURN_CAST_ERROR(cc->expr,
"%s cannot be cast to %s as its elements has a greater default alignment, but you can use a bitcast.",
type_quoted_error_string(cc->expr->type), type_quoted_error_string(cc->to_type));
}
if (!is_explicit) return sema_cast_error(cc, true, is_silent);
return true;
UNREACHABLE
}
static bool rule_arr_to_arr(CastContext *cc, bool is_explicit, bool is_silent)
{
if (!rule_slice_to_slice(cc, is_explicit, is_silent)) return false;
if (type_flatten(cc->to)->array.len != type_flatten(cc->from)->array.len)
{
if (is_silent) return false;
RETURN_CAST_ERROR(cc->expr, "Arrays of different lengths may not be converted.");
}
if (type_size(cc->from) != type_size(cc->to))
{
if (is_silent) return false;
RETURN_CAST_ERROR(cc->expr, "Arrays of different size may not be converted.");
}
return rule_slice_to_slice(cc, is_explicit, is_silent);
return true;
}
static bool rule_arr_to_vec(CastContext *cc, bool is_explicit, bool is_silent)

View File

@@ -1627,8 +1627,14 @@ TypeCmpResult type_array_element_is_equivalent(SemaContext *context, Type *eleme
}
switch (element1->type_kind)
{
case TYPE_FUNC_PTR:
if (element2 == type_voidptr) return TYPE_SAME;
if (element1->type_kind != TYPE_FUNC_PTR) return TYPE_MISMATCH;
if (element1->pointer->function.prototype->raw_type == element2->pointer->function.prototype->raw_type) return TYPE_SAME;
return TYPE_MISMATCH;
case TYPE_POINTER:
if (element2->type_kind != TYPE_POINTER) return TYPE_MISMATCH;
if (element2->type_kind == TYPE_FUNC_PTR && type_voidptr == element1) return TYPE_SAME;
if (!type_is_pointer(element2)) return TYPE_MISMATCH;
return type_is_pointer_equivalent(context, element1, element2, is_explicit);
case TYPE_STRUCT:
if (is_explicit) return type_is_structurally_equivalent(element1, element2) ? TYPE_SAME : TYPE_MISMATCH;