Skip to content

Commit

Permalink
Incorrect subscript resolution #1519
Browse files Browse the repository at this point in the history
  • Loading branch information
lerno committed Oct 4, 2024
1 parent 6fabeca commit cfc1d0d
Show file tree
Hide file tree
Showing 10 changed files with 78 additions and 32 deletions.
1 change: 1 addition & 0 deletions releasenotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
60 changes: 32 additions & 28 deletions src/compiler/sema_expr.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 "
Expand Down Expand Up @@ -2897,16 +2924,16 @@ 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)
{
if (check_valid) goto VALID_FAIL_POISON;
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.
Expand All @@ -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)
Expand Down
1 change: 1 addition & 0 deletions src/compiler/types.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion test/test_suite/expressions/fail_index_usize.c3
Original file line number Diff line number Diff line change
@@ -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
}
1 change: 1 addition & 0 deletions test/test_suite/subarrays/slice_offset.c3t
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// #target: macos-x64
fn void test()
{
int[3] x = { 1, 2, 3 };
Expand Down
2 changes: 1 addition & 1 deletion test/test_suite/subarrays/slice_offset_neg_end.c3t
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@

// #target: macos-x64
fn void test()
{
int[3] x = { 1, 2, 3 };
Expand Down
1 change: 1 addition & 0 deletions test/test_suite/subarrays/slice_offset_neg_start.c3t
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// #target: macos-x64
fn void test()
{
int[3] x = { 1, 2, 3 };
Expand Down
1 change: 1 addition & 0 deletions test/test_suite/subarrays/slice_start.c3t
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// #target: macos-x64
fn void test()
{
int[3] x = { 1, 2, 3 };
Expand Down
37 changes: 37 additions & 0 deletions test/test_suite/subarrays/subscript_check_1519.c3t
Original file line number Diff line number Diff line change
@@ -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
}
4 changes: 2 additions & 2 deletions test/unit/stdlib/string.c3
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}

0 comments on commit cfc1d0d

Please sign in to comment.