diff --git a/releasenotes.md b/releasenotes.md index 0f630fce5..f679ed46e 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -11,6 +11,7 @@ ### Fixes - `Unsupported int[*] $x = { 1, 2, 3, 4 }` #1489. - Unexpected compile error using a typed constant with `copysign` #1517 +- Incorrect subscript resolution #1519. ### Stdlib changes - Remove unintended print of `char[]` as String diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 99c38c2c1..9217b5118 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -2846,13 +2846,40 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr, // 3. Check failability due to value. bool optional = IS_OPTIONAL(subscripted); - Type *underlying_type = type_flatten(subscripted->type); + Decl *overload = NULL; + Type *index_type = NULL; + Expr *current_expr; + Type *current_type = subscripted->type->canonical; + if (current_type == type_untypedlist) + { + current_expr = subscripted; + } + else + { + current_expr = sema_expr_find_index_type_or_overload_for_subscript(context, subscripted, check, &index_type, &overload); + if (!overload && !index_type && is_eval_ref) + { + // Maybe there is a [] overload? + if (sema_expr_find_index_type_or_overload_for_subscript(context, subscripted, check, &index_type, &overload)) + { + if (check_valid) goto VALID_FAIL_POISON; + RETURN_SEMA_ERROR(expr, "A function or macro with '@operator(&[])' is not defined for %s, " + "so you need && to take the address of the temporary.", + type_quoted_error_string(subscripted->type)); + } + } + if (!index_type) + { + if (check_valid) goto VALID_FAIL_POISON; + RETURN_SEMA_ERROR(expr, "Indexing a value of type %s is not possible.", type_quoted_error_string(subscripted->type)); + } + if (!overload) current_type = type_flatten(current_expr->type); + } - Type *current_type = underlying_type; assert(current_type == current_type->canonical); int64_t index_value = -1; bool start_from_end = expr->subscript_expr.index.start_from_end; - if (start_from_end && (underlying_type->type_kind == TYPE_POINTER || underlying_type->type_kind == TYPE_FLEXIBLE_ARRAY)) + if (start_from_end && (current_type->type_kind == TYPE_POINTER || current_type->type_kind == TYPE_FLEXIBLE_ARRAY)) { if (check_valid) goto VALID_FAIL_POISON; RETURN_SEMA_ERROR(index, "Indexing from the end is not allowed for pointers " @@ -2897,8 +2924,9 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr, (long long) size - 1); } } + // 4. If we are indexing into a complist - if (underlying_type == type_untypedlist) + if (current_type == type_untypedlist) { if (is_eval_ref) { @@ -2906,7 +2934,6 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr, RETURN_SEMA_ERROR(subscripted, "You need to use && to take the address of a temporary."); } // 4a. This may either be an initializer list or a CT value - Expr *current_expr = subscripted; while (subscripted->expr_kind == EXPR_CT_IDENT) current_expr = current_expr->ct_ident_expr.decl->var.init_expr; // 4b. Now we need to check that we actually have a valid type. @@ -2921,29 +2948,6 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr, } if (!sema_cast_rvalue(context, subscripted)) return false; - Decl *overload = NULL; - Type *index_type = NULL; - Expr *current_expr = sema_expr_find_index_type_or_overload_for_subscript(context, subscripted, check, &index_type, &overload); - if (!index_type) - { - if (!overload && is_eval_ref) - { - // Maybe there is a [] overload? - if (sema_expr_find_index_type_or_overload_for_subscript(context, - subscripted, - check, - &index_type, - &overload)) - { - if (check_valid) goto VALID_FAIL_POISON; - RETURN_SEMA_ERROR(expr, "A function or macro with '@operator(&[])' is not defined for %s, " - "so you need && to take the address of the temporary.", - type_quoted_error_string(subscripted->type)); - } - } - if (check_valid) goto VALID_FAIL_POISON; - RETURN_SEMA_ERROR(subscripted, "Cannot index %s.", type_quoted_error_string(subscripted->type)); - } if (overload) { if (start_from_end) diff --git a/src/compiler/types.c b/src/compiler/types.c index 918055d59..2bca133cd 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -1079,6 +1079,7 @@ bool type_is_user_defined(Type *type) Type *type_get_indexed_type(Type *type) { RETRY: + if (type == type_voidptr) return NULL; switch (type->type_kind) { case TYPE_POINTER: diff --git a/test/test_suite/expressions/fail_index_usize.c3 b/test/test_suite/expressions/fail_index_usize.c3 index 80e6f0c40..438d83cde 100644 --- a/test/test_suite/expressions/fail_index_usize.c3 +++ b/test/test_suite/expressions/fail_index_usize.c3 @@ -1,5 +1,5 @@ fn void test(int* array, usz n) { array[n] = 33; - n[array] = 33; // #error: Cannot index + n[array] = 33; // #error: Indexing a value of type } diff --git a/test/test_suite/subarrays/slice_offset.c3t b/test/test_suite/subarrays/slice_offset.c3t index 55203e904..7bb061d9e 100644 --- a/test/test_suite/subarrays/slice_offset.c3t +++ b/test/test_suite/subarrays/slice_offset.c3t @@ -1,3 +1,4 @@ +// #target: macos-x64 fn void test() { int[3] x = { 1, 2, 3 }; diff --git a/test/test_suite/subarrays/slice_offset_neg_end.c3t b/test/test_suite/subarrays/slice_offset_neg_end.c3t index e36abf9be..bb3333398 100644 --- a/test/test_suite/subarrays/slice_offset_neg_end.c3t +++ b/test/test_suite/subarrays/slice_offset_neg_end.c3t @@ -1,4 +1,4 @@ - +// #target: macos-x64 fn void test() { int[3] x = { 1, 2, 3 }; diff --git a/test/test_suite/subarrays/slice_offset_neg_start.c3t b/test/test_suite/subarrays/slice_offset_neg_start.c3t index 5414d6e86..18b1faea2 100644 --- a/test/test_suite/subarrays/slice_offset_neg_start.c3t +++ b/test/test_suite/subarrays/slice_offset_neg_start.c3t @@ -1,3 +1,4 @@ +// #target: macos-x64 fn void test() { int[3] x = { 1, 2, 3 }; diff --git a/test/test_suite/subarrays/slice_start.c3t b/test/test_suite/subarrays/slice_start.c3t index 6acea276a..91a82af65 100644 --- a/test/test_suite/subarrays/slice_start.c3t +++ b/test/test_suite/subarrays/slice_start.c3t @@ -1,3 +1,4 @@ +// #target: macos-x64 fn void test() { int[3] x = { 1, 2, 3 }; diff --git a/test/test_suite/subarrays/subscript_check_1519.c3t b/test/test_suite/subarrays/subscript_check_1519.c3t new file mode 100644 index 000000000..e64bdeedc --- /dev/null +++ b/test/test_suite/subarrays/subscript_check_1519.c3t @@ -0,0 +1,37 @@ +// #target: macos-x64 +module test; +import std::collections::list; +macro @test_list(a) +{ + var $Type = $typeof(a); + $if $defined(a[0]) &&& $Type.typeid == List(<$typeof(a[0])>).typeid: + return 1; + $else + return 0; + $endif +} + +fn int main(String[] args) +{ + DString str = dstring::new("test"); + return @test_list(str); +} + +/* #expect: test.ll + +define i32 @test.main(ptr %0, i64 %1) #0 { +entry: + %args = alloca %"char[][]", align 8 + %str = alloca ptr, align 8 + %a = alloca ptr, align 8 + store ptr %0, ptr %args, align 8 + %ptradd = getelementptr inbounds i8, ptr %args, i64 8 + store i64 %1, ptr %ptradd, align 8 + %lo = load i64, ptr @std.core.mem.allocator.thread_allocator, align 8 + %hi = load ptr, ptr getelementptr inbounds (i8, ptr @std.core.mem.allocator.thread_allocator, i64 8), align 8 + %2 = call ptr @std.core.dstring.new(ptr @.str, i64 4, i64 %lo, ptr %hi) + store ptr %2, ptr %str, align 8 + %3 = load ptr, ptr %str, align 8 + store ptr %3, ptr %a, align 8 + ret i32 0 +} \ No newline at end of file diff --git a/test/unit/stdlib/string.c3 b/test/unit/stdlib/string.c3 index b6835cacb..da46afd27 100644 --- a/test/unit/stdlib/string.c3 +++ b/test/unit/stdlib/string.c3 @@ -8,12 +8,12 @@ fn void! test_clear() @test s.append_repeat('x', 63); assert(s.capacity() == 64); assert(s.len() == 63); - char* addr = &s[0]; + char* addr = (char*)s.str_view(); s.clear(); assert(s.capacity() == 64); assert(s.len() == 0); s.append_repeat('x', 63); assert(s.capacity() == 64); assert(s.len() == 63); - assert(addr == &s[0]); + assert(addr == (char*)s.str_view()); } \ No newline at end of file