Casting const bytes to vector with different element size was broken #2787

This commit is contained in:
Christoffer Lerno
2026-01-21 12:56:25 +01:00
parent 61c939059d
commit a126a25d66
6 changed files with 105 additions and 26 deletions

View File

@@ -20,16 +20,6 @@
- Module-based generics using {} is deprecated.
- Create optional with `~` instead of `?`. `return io::EOF?;` becomes `return io::EOF~`.
- Deprecated use of `?` to create optional.
- Vectors not converted to arrays when passed as raw vaargs. #2776
- Second value in switch range not checked properly, causing an error on non-const values. #2777
- Broken cast from fault to array pointer #2778.
- $typeof untyped list crashes when trying to create typeid from it. #2779
- Recursive constant definition not properly detected, leading to assert #2780
- Failed to reject void compile time variables, leading to crash. #2781
- Inferring the size of a slice with an inner inferred array using {} isn't detected as error #2783
- Bug in sysv abi when passing union in with floats #2784
- When a global const has invalid attributes, handling is incorrect, leading to a crash #2785.
- `int? ?` was not correctly handled. #2786
### Fixes
- Regression with npot vector in struct triggering an assert #2219.
@@ -98,6 +88,17 @@
- When an `int[*][6]` was given too few values, the compiler would assert instead of giving an error. #2771
- Inferring length from a slice was accidentally not an error.
- Eager evaluation of macro arguments would break inferred arrays on some platforms. #2771.
- Vectors not converted to arrays when passed as raw vaargs. #2776
- Second value in switch range not checked properly, causing an error on non-const values. #2777
- Broken cast from fault to array pointer #2778.
- $typeof untyped list crashes when trying to create typeid from it. #2779
- Recursive constant definition not properly detected, leading to assert #2780
- Failed to reject void compile time variables, leading to crash. #2781
- Inferring the size of a slice with an inner inferred array using {} isn't detected as error #2783
- Bug in sysv abi when passing union in with floats #2784
- When a global const has invalid attributes, handling is incorrect, leading to a crash #2785.
- `int? ?` was not correctly handled. #2786
- Casting const bytes to vector with different element size was broken #2787
### Stdlib changes
- Add `ThreadPool` join function to wait for all threads to finish in the pool without destroying the threads.

View File

@@ -689,6 +689,11 @@ static inline TypeInfo *parse_vector_type_index(ParseContext *c, TypeInfo *type)
PRINT_ERROR_HERE("Only '@simd' is a valid attribute, found '%s'.", symstr(c));
return poisoned_type_info;
}
if (vector->kind == TYPE_INFO_INFERRED_VECTOR)
{
PRINT_ERROR_HERE("The '@simd' attribute cannot be used on an inferred vector type.");
return poisoned_type_info;
}
advance(c);
vector->is_simd = true;
}

View File

@@ -25,9 +25,10 @@ typedef struct // NOLINT
static bool sema_error_const_int_out_of_range(CastContext *cc, Expr *expr, Expr *problem, Type *to_type);
static Expr *recursive_may_narrow(Expr *expr, Type *type);
static void expr_recursively_rewrite_untyped_list(Expr *expr, Type *to_type);
static void expr_rewrite_bytes_to_const_initializer(Expr *expr, Type *target_type);
static void vector_const_initializer_convert_to_type(ConstInitializer *initializer, Type *to_type);
static bool cast_is_allowed(CastContext *cc, bool is_explicit, bool is_silent);
static void cast_arr_to_vec(Expr *expr, Type *to_type);
static bool cast_if_valid(SemaContext *context, Expr *expr, Type *to_type, bool is_explicit, bool is_silent,
bool is_binary_conversion);
INLINE ConvGroup type_to_group(Type *type);
@@ -2034,7 +2035,7 @@ static void cast_vec_to_arr(Expr *expr, Type *to_type)
*/
static void cast_vec_to_vec(Expr *expr, Type *to_type)
{
if (!sema_cast_const(expr))
if (!sema_cast_const(expr) || !expr_is_const_initializer(expr))
{
// Extract indexed types.
Type *from_type = type_flatten(expr->type);
@@ -2376,7 +2377,7 @@ static void cast_vecarr_to_slice(Expr *expr, Type *to_type)
}
UNREACHABLE_VOID
}
static void cast_slice_to_vecarr(Expr *expr, Type *to_type)
static void cast_slice_to_arr(Expr *expr, Type *to_type)
{
if (!sema_cast_const(expr))
{
@@ -2402,6 +2403,54 @@ static void cast_slice_to_vecarr(Expr *expr, Type *to_type)
expr->type = to_type;
}
static void expr_rewrite_bytes_to_const_initializer(Expr *expr, Type *target_type)
{
Type *flat_vec = type_flatten(target_type);
Type *base = type_flatten(flat_vec->array.base);
ConstInitializer **inits = MALLOC(sizeof(ConstInitializer*) * expr->const_expr.bytes.len);
for (int i = 0; i < expr->const_expr.bytes.len; i++)
{
Expr *int_expr = expr_new_const_int(expr->span, base, (unsigned char)expr->const_expr.bytes.ptr[i]);
ConstInitializer *init = const_init_new_value(int_expr);
inits[i] = init;
}
ASSERT(inits);
Type *type = type_get_vector(base, flat_vec->type_kind, expr->const_expr.bytes.len);
ConstInitializer *slice = const_init_new_array_full(type, inits);
expr_rewrite_const_initializer(expr, type, slice);
}
static void cast_slice_to_vec(Expr *expr, Type *to_type)
{
if (!sema_cast_const(expr))
{
switch (expr->expr_kind)
{
case EXPR_SLICE:
{
expr->inner_expr = expr_copy(expr);
expr->expr_kind = EXPR_SLICE_TO_VEC_ARRAY;
expr->type = to_type;
expr->resolve_status = RESOLVE_DONE;
return;
}
default:
UNREACHABLE_VOID;
}
}
if (expr_is_const_bytes(expr) || expr_is_const_string(expr))
{
expr_rewrite_bytes_to_const_initializer(expr, to_type);
}
if (expr_is_const_slice(expr))
{
expr->const_expr.const_kind = CONST_INITIALIZER;
}
ASSERT(expr_is_const(expr));
expr->type = to_type;
}
static void cast_slice_to_infer(Expr *expr, Type *to_type)
{
ArraySize len = sema_len_from_const(expr);
@@ -2435,18 +2484,16 @@ static void cast_arr_to_vec(Expr *expr, Type *to_type)
Type *to_temp = index_vec == index_arr ? to_type : type_get_vector(index_arr, to_type->canonical->type_kind, type_flatten(expr->type)->array.len);
if (sema_cast_const(expr))
{
// For the array -> vector this is always a simple rewrite of type.
if (expr->const_expr.const_kind == CONST_BYTES || expr->const_expr.const_kind == CONST_STRING)
{
expr->type = to_temp;
}
else
{
ASSERT(expr->const_expr.const_kind == CONST_INITIALIZER);
ConstInitializer *list = expr->const_expr.initializer;
list->type = type_flatten(to_temp);
expr->type = to_temp;
expr_rewrite_bytes_to_const_initializer(expr, to_type);
expr->type = to_type;
return;
}
ASSERT(expr->const_expr.const_kind == CONST_INITIALIZER);
ConstInitializer *list = expr->const_expr.initializer;
list->type = type_flatten(to_temp);
expr->type = to_temp;
}
else
{
@@ -2511,7 +2558,8 @@ static void cast_typeid_to_bool(Expr *expr, Type *to_type) { expr_rewrite_int_to
#define TI2IN &cast_typeid_to_int
#define TI2PT &cast_typeid_to_ptr
#define AF2BO &cast_anyfault_to_bool
#define SL2VA &cast_slice_to_vecarr
#define SL2VC &cast_slice_to_vec
#define SL2AR &cast_slice_to_arr
#define VA2SL &cast_vecarr_to_slice
#define XX2VO &cast_all_to_void
#define SL2FE &cast_slice_to_infer
@@ -2596,7 +2644,7 @@ CastFunction cast_function[CONV_LAST + 1][CONV_LAST + 1] = {
{XX2VO, 0, IN2BO, IN2IN, IN2FP, IN2PT, 0, EX2VC, IA2BS, 0, 0, 0, 0, 0, 0, IN2EN, 0, IN2PT, 0, 0, IN2PT, IN2PT, 0, 0 }, // INT
{XX2VO, 0, FP2BO, FP2IN, FP2FP, 0, 0, EX2VC, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // FLOAT
{XX2VO, 0, PT2BO, PT2IN, 0, PT2PT, 0, EX2VC, 0, 0, 0, 0, 0, PT2AY, PT2AY, 0, 0, 0, 0, 0, PT2PT, PT2PT, PT2FE, 0 }, // PTR
{XX2VO, 0, SL2BO, 0, 0, SL2PT, SL2SL, SL2VA, 0, 0, SL2VA, 0, 0, 0, 0, 0, 0, 0, 0, 0, SL2PT, SL2PT, SL2FE, 0 }, // SLICE
{XX2VO, 0, SL2BO, 0, 0, SL2PT, SL2SL, SL2VC, 0, 0, SL2AR, 0, 0, 0, 0, 0, 0, 0, 0, 0, SL2PT, SL2PT, SL2FE, 0 }, // SLICE
{XX2VO, 0, 0, 0, 0, 0, VA2SL, VC2VC, 0, 0, VC2AR, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, VA2FE, 0 }, // VECTOR
{XX2VO, 0, BS2BO, BS2IA, 0, 0, 0, 0, 0, 0, BS2IA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // BITSTRUCT
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // DISTINCT

View File

@@ -0,0 +1,15 @@
// #target: linux-x64
module test;
long[<*>] a = x'dead';
long[<*>] a2 = "hello world blah1";
fn int main()
{
a[0] = a2[0];
return 0;
}
/* #expect: test.ll
@test.a = local_unnamed_addr global <2 x i64> <i64 222, i64 173>, align 16
@test.a2 = local_unnamed_addr global <17 x i64> <i64 104, i64 101, i64 108, i64 108, i64 111, i64 32, i64 119, i64 111, i64 114, i64 108, i64 100, i64 32, i64 98, i64 108, i64 97, i64 104, i64 49>, align 256

View File

@@ -0,0 +1,11 @@
// #target: linux-x64
module test;
long[<*>] a = x'dead';
long[<*>] a2 = "hello world blah";
/* #expect: test.ll
@test.a = local_unnamed_addr global <2 x i64> <i64 222, i64 173>, align 16
@test.a2 = local_unnamed_addr global <16 x i64> <i64 104, i64 101, i64 108, i64 108, i64 111, i64 32, i64 119, i64 111, i64 114, i64 108, i64 100, i64 32, i64 98, i64 108, i64 97, i64 104>, align 128

View File

@@ -9,8 +9,7 @@ fn void main()
}
/* #expect: test.ll
@test.fooy = local_unnamed_addr global [2 x i8] c"\DE\AD", align 2
@test.fooy = local_unnamed_addr global <2 x i8> <i8 -34, i8 -83>, align 2
@test.fooy2 = local_unnamed_addr global <2 x i8> <i8 -34, i8 -83>, align 2
define void @test.main() #0 {