mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Incorrect subscript resolution #1519
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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,3 +1,4 @@
|
||||
// #target: macos-x64
|
||||
fn void test()
|
||||
{
|
||||
int[3] x = { 1, 2, 3 };
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
|
||||
// #target: macos-x64
|
||||
fn void test()
|
||||
{
|
||||
int[3] x = { 1, 2, 3 };
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// #target: macos-x64
|
||||
fn void test()
|
||||
{
|
||||
int[3] x = { 1, 2, 3 };
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// #target: macos-x64
|
||||
fn void test()
|
||||
{
|
||||
int[3] x = { 1, 2, 3 };
|
||||
|
||||
37
test/test_suite/subarrays/subscript_check_1519.c3t
Normal file
37
test/test_suite/subarrays/subscript_check_1519.c3t
Normal file
@@ -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
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
Reference in New Issue
Block a user