mirror of
https://github.com/odin-lang/Odin.git
synced 2026-08-14 09:44:26 +00:00
Merge pull request #7251 from kalsprite/s003
Validate floating-point array counts as integers
This commit is contained in:
@@ -2846,9 +2846,14 @@ gb_internal i64 check_array_count(CheckerContext *ctx, Operand *o, Ast *e) {
|
||||
}
|
||||
Type *type = core_type(o->type);
|
||||
if (is_type_untyped(type) || is_type_integer(type)) {
|
||||
if (o->value.kind == ExactValue_Integer) {
|
||||
BigInt count = o->value.value_integer;
|
||||
if (big_int_is_neg(&o->value.value_integer)) {
|
||||
ExactValue value = o->value;
|
||||
if (value.kind == ExactValue_Float) {
|
||||
// NOTE: an integral float is a valid count, but it must be range checked as an integer
|
||||
value = exact_value_to_integer(value);
|
||||
}
|
||||
if (value.kind == ExactValue_Integer) {
|
||||
BigInt count = value.value_integer;
|
||||
if (big_int_is_neg(&count)) {
|
||||
gbAllocator a = heap_allocator();
|
||||
String str = big_int_to_string(a, &count);
|
||||
error(e, "Invalid negative array count, %.*s", LIT(str));
|
||||
@@ -2864,12 +2869,6 @@ gb_internal i64 check_array_count(CheckerContext *ctx, Operand *o, Ast *e) {
|
||||
error(e, "Array count too large, %.*s", LIT(str));
|
||||
gb_free(a, str.text);
|
||||
return 0;
|
||||
} else if (o->value.kind == ExactValue_Float) {
|
||||
u64 u = cast(u64)o->value.value_float;
|
||||
f64 f = cast(f64)u;
|
||||
if (f == o->value.value_float) {
|
||||
return u;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -419,6 +419,12 @@ gb_internal ExactValue exact_value_to_integer(ExactValue v) {
|
||||
case ExactValue_Integer:
|
||||
return v;
|
||||
case ExactValue_Float: {
|
||||
f64 const min = cast(f64)I64_MIN; // -2^63
|
||||
f64 const max = -min; // 2^63, one past I64_MAX
|
||||
// NOTE: the conversion below is undefined outside of this range, NaN included
|
||||
if (!(v.value_float >= min && v.value_float < max)) {
|
||||
break;
|
||||
}
|
||||
i64 i = cast(i64)v.value_float;
|
||||
f64 f = cast(f64)i;
|
||||
if (f == v.value_float) {
|
||||
|
||||
25
tests/internal/test_array_count.odin
Normal file
25
tests/internal/test_array_count.odin
Normal file
@@ -0,0 +1,25 @@
|
||||
package test_internal
|
||||
|
||||
import "core:testing"
|
||||
|
||||
@(test)
|
||||
array_count_from_integral_float :: proc(t: ^testing.T) {
|
||||
testing.expect_value(t, len([3.0]u8{}), 3)
|
||||
testing.expect_value(t, len([0.0]u8{}), 0)
|
||||
testing.expect_value(t, size_of([3.0]u32), 12)
|
||||
|
||||
// folded constant expressions
|
||||
Halved :: 6.0 / 2.0
|
||||
Summed :: 1.5 + 1.5
|
||||
testing.expect_value(t, len([Halved]u8{}), 3)
|
||||
testing.expect_value(t, len([Summed]u8{}), 3)
|
||||
|
||||
// NOTE: keep below one BigInt limb: 2^28 on windows, 2^60 on linux
|
||||
testing.expect_value(t, len([65536.0]struct{}{}), 1 << 16)
|
||||
|
||||
testing.expect_value(t, size_of(matrix[2.0, 3.0]f32), 24)
|
||||
testing.expect_value(t, size_of(#simd[4.0]u8), 4)
|
||||
|
||||
Sparse :: [2.0]u8
|
||||
testing.expect_value(t, len(Sparse{1, 2}), 2)
|
||||
}
|
||||
Reference in New Issue
Block a user