Correctly handle known length slices with index checks.

This commit is contained in:
Christoffer Lerno
2025-01-13 02:30:35 +01:00
parent 27970085e5
commit de04c52379

View File

@@ -170,7 +170,6 @@ static inline void sema_create_const_membersof(SemaContext *context, Expr *expr,
AlignSize offset);
static inline void sema_create_const_methodsof(SemaContext *context, Expr *expr, Type *type);
static inline int64_t expr_get_index_max(Expr *expr);
static inline bool expr_both_any_integer_or_integer_vector(Expr *left, Expr *right);
static inline bool expr_both_any_integer_or_integer_bool_vector(Expr *left, Expr *right);
static inline bool expr_both_const(Expr *left, Expr *right);
@@ -3075,8 +3074,9 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr,
"and flexible array members.");
}
int64_t size;
if (expr_is_const_int(index) && (size = expr_get_index_max(subscripted)) >= 0)
ArrayIndex size;
bool check_len = !context->call_env.in_no_eval || current_type == type_untypedlist;
if (check_len && expr_is_const_int(index) && (size = sema_len_from_expr(current_expr)) >= 0)
{
// 4c. And that it's in range.
if (int_is_neg(index->const_expr.ixx))
@@ -3124,7 +3124,7 @@ 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
while (subscripted->expr_kind == EXPR_CT_IDENT) current_expr = current_expr->ct_ident_expr.decl->var.init_expr;
while (current_expr->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.
if (index_value < 0)
@@ -3132,7 +3132,10 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr,
if (check_valid) goto VALID_FAIL_POISON;
RETURN_SEMA_ERROR(index, "To subscript an untyped list a compile time integer index is needed.");
}
if (check == CHECK_LVALUE) TODO;
if (check == CHECK_LVALUE)
{
REMINDER("Fix LVALUE");
}
expr_replace(expr, current_expr->const_expr.untyped_list[index_value]);
return true;
}
@@ -9260,13 +9263,19 @@ static inline bool sema_expr_analyse_castable(SemaContext *context, Expr *expr)
{
ASSERT_SPAN(expr, expr->resolve_status == RESOLVE_RUNNING);
TypeInfo *type_info = type_infoptr(expr->castable_expr.type);
if (!sema_resolve_type_info(context, type_info, RESOLVE_TYPE_ALLOW_INFER)) return false;
bool in_no_eval = context->call_env.in_no_eval;
context->call_env.in_no_eval = true;
if (!sema_resolve_type_info(context, type_info, RESOLVE_TYPE_ALLOW_INFER)) goto FAILED;
Type *type = type_info->type;
Expr *inner = exprptr(expr->castable_expr.expr);
if (!sema_analyse_inferred_expr(context, type, inner)) return false;
if (!sema_analyse_inferred_expr(context, type, inner)) goto FAILED;
bool ok = may_cast(context, inner, type, !expr->castable_expr.is_assign, true);
expr_rewrite_const_bool(expr, type_bool, ok);
context->call_env.in_no_eval = in_no_eval;
return true;
FAILED:
context->call_env.in_no_eval = in_no_eval;
return false;
}
@@ -9870,24 +9879,28 @@ bool sema_analyse_expr_value(SemaContext *context, Expr *expr)
}
}
#define RESOLVE(expr__, check__) \
do { \
Expr *expr_temp__ = expr__; \
switch (expr_temp__->resolve_status) { \
case RESOLVE_NOT_DONE: \
expr_temp__->resolve_status = RESOLVE_RUNNING; \
if (!check__) return expr_poison(expr_temp__); \
expr_temp__->resolve_status = RESOLVE_DONE; \
return true; \
case RESOLVE_RUNNING: \
SEMA_ERROR(expr, "Recursive resolution of expression"); \
return expr_poison(expr_temp__); \
case RESOLVE_DONE: \
return expr_ok(expr_temp__); \
default: \
UNREACHABLE \
} } while (0);
static inline bool sema_analyse_expr_check(SemaContext *context, Expr *expr, CheckType check)
{
ASSERT0(expr);
switch (expr->resolve_status)
{
case RESOLVE_NOT_DONE:
expr->resolve_status = RESOLVE_RUNNING;
if (!sema_analyse_expr_dispatch(context, expr, check)) return expr_poison(expr);
expr->resolve_status = RESOLVE_DONE;
return true;
case RESOLVE_RUNNING:
SEMA_ERROR(expr, "Recursive resolution of expression");
return expr_poison(expr);
case RESOLVE_DONE:
return expr_ok(expr);
default:
UNREACHABLE
}
RESOLVE(expr, sema_analyse_expr_dispatch(context, expr, check));
}
bool sema_analyse_expr_address(SemaContext *context, Expr *expr)
@@ -10029,36 +10042,6 @@ bool sema_cast_const(Expr *expr)
UNREACHABLE
}
static inline int64_t expr_get_index_max(Expr *expr)
{
if (expr_is_const_untyped_list(expr))
{
return vec_size(expr->const_expr.untyped_list);
}
Type *type = expr->type;
RETRY:
switch (type->type_kind)
{
case TYPE_TYPEDEF:
type = type->canonical;
goto RETRY;
case TYPE_DISTINCT:
type = type->decl->distinct->type;
goto RETRY;
case TYPE_UNTYPED_LIST:
UNREACHABLE;
case TYPE_ARRAY:
case TYPE_VECTOR:
return type->array.len;
case TYPE_OPTIONAL:
type = type->optional;
goto RETRY;
default:
return -1;
}
UNREACHABLE
}
bool sema_analyse_inferred_expr(SemaContext *context, Type *infer_type, Expr *expr)
{
infer_type = type_no_optional(infer_type);