Fix #806, and also makes sure that things like FOO.x.a is a compile time value.

This commit is contained in:
Christoffer Lerno
2023-07-01 16:28:22 +02:00
parent 9102fc6032
commit 70ea6ce04b
8 changed files with 131 additions and 12 deletions

View File

@@ -82,8 +82,8 @@ fn void LinkedList.link_last(LinkedList* list, Type value) @private
list.size++; list.size++;
} }
fn Type! peek(LinkedList* list) => list.first() @inline; fn Type! LinkedList.peek(LinkedList* list) => list.first() @inline;
fn Type! peek_last(LinkedList* list) => list.last() @inline; fn Type! LinkedList.peek_last(LinkedList* list) => list.last() @inline;
fn Type! LinkedList.first(LinkedList *list) fn Type! LinkedList.first(LinkedList *list)
{ {

View File

@@ -406,6 +406,8 @@ static inline bool expr_unary_addr_is_constant_eval(Expr *expr, ConstantEvalKind
Expr *inner = expr->unary_expr.expr; Expr *inner = expr->unary_expr.expr;
switch (inner->expr_kind) switch (inner->expr_kind)
{ {
case EXPR_ACCESS:
return expr_is_constant_eval(inner, eval_kind);
case EXPR_CONST: case EXPR_CONST:
case EXPR_INITIALIZER_LIST: case EXPR_INITIALIZER_LIST:
case EXPR_DESIGNATED_INITIALIZER_LIST: case EXPR_DESIGNATED_INITIALIZER_LIST:

View File

@@ -138,7 +138,7 @@ INLINE bool sema_call_expand_arguments(SemaContext *context, CalledDecl *callee,
static inline int sema_call_find_index_of_named_parameter(SemaContext *context, Decl **func_params, Expr *expr); static inline int sema_call_find_index_of_named_parameter(SemaContext *context, Decl **func_params, Expr *expr);
static inline bool sema_call_check_contract_param_match(SemaContext *context, Decl *param, Expr *expr); static inline bool sema_call_check_contract_param_match(SemaContext *context, Decl *param, Expr *expr);
static bool sema_call_analyse_body_expansion(SemaContext *macro_context, Expr *call); static bool sema_call_analyse_body_expansion(SemaContext *macro_context, Expr *call);
static bool sema_flattened_expr_is_const_initializer(SemaContext *context, Expr *expr);
static bool sema_slice_len_is_in_range(SemaContext *context, Type *type, Expr *len_expr, bool from_end, bool *remove_from_end); static bool sema_slice_len_is_in_range(SemaContext *context, Type *type, Expr *len_expr, bool from_end, bool *remove_from_end);
static bool sema_slice_index_is_in_range(SemaContext *context, Type *type, Expr *index_expr, bool end_index, bool from_end, bool *remove_from_end); static bool sema_slice_index_is_in_range(SemaContext *context, Type *type, Expr *index_expr, bool end_index, bool from_end, bool *remove_from_end);
@@ -2628,7 +2628,7 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr,
} }
else else
{ {
if (expr_is_const_initializer(current_expr) && expr_is_const(index)) if (sema_flattened_expr_is_const(context, index) && sema_flattened_expr_is_const_initializer(context, current_expr))
{ {
if (sema_subscript_rewrite_index_const_list(current_expr, index, expr)) return true; if (sema_subscript_rewrite_index_const_list(current_expr, index, expr)) return true;
} }
@@ -3398,7 +3398,8 @@ static bool sema_expr_rewrite_typeid_call(Expr *expr, Expr *typeid, TypeIdInfoKi
static bool sema_expr_rewrite_to_typeid_property(SemaContext *context, Expr *expr, Expr *typeid, const char *kw) static bool sema_expr_rewrite_to_typeid_property(SemaContext *context, Expr *expr, Expr *typeid, const char *kw)
{ {
TypeProperty property = type_property_by_name(kw); TypeProperty property = type_property_by_name(kw);
if (typeid->expr_kind == EXPR_CONST)
if (sema_flattened_expr_is_const(context, typeid))
{ {
Type *type = typeid->const_expr.typeid; Type *type = typeid->const_expr.typeid;
return sema_expr_rewrite_to_type_property(context, expr, type, property, type); return sema_expr_rewrite_to_type_property(context, expr, type, property, type);
@@ -3625,6 +3626,52 @@ static inline bool sema_expr_analyse_swizzle(SemaContext *context, Expr *expr, E
return true; return true;
} }
static inline void sema_expr_flatten_const(SemaContext *context, Expr *expr)
{
if (expr->expr_kind != EXPR_IDENTIFIER) return;
Decl *ident = expr->identifier_expr.decl;
if (ident->decl_kind != DECL_VAR) return;
switch (ident->var.kind)
{
case VARDECL_CONST:
case VARDECL_LOCAL_CT:
case VARDECL_PARAM_CT:
break;
case VARDECL_GLOBAL:
case VARDECL_LOCAL:
case VARDECL_PARAM:
case VARDECL_MEMBER:
case VARDECL_BITMEMBER:
case VARDECL_PARAM_REF:
case VARDECL_PARAM_EXPR:
case VARDECL_UNWRAPPED:
case VARDECL_ERASE:
case VARDECL_REWRAPPED:
case VARDECL_PARAM_CT_TYPE:
case VARDECL_LOCAL_CT_TYPE:
return;
}
Expr *init_expr = ident->var.init_expr;
if (!init_expr) return;
sema_expr_flatten_const(context, init_expr);
if (expr_is_const(init_expr))
{
expr_replace(expr, expr_copy(init_expr));
}
}
bool sema_flattened_expr_is_const(SemaContext *context, Expr *expr)
{
sema_expr_flatten_const(context, expr);
return expr_is_const(expr);
}
static bool sema_flattened_expr_is_const_initializer(SemaContext *context, Expr *expr)
{
sema_expr_flatten_const(context, expr);
return expr_is_const_initializer(expr);
}
/** /**
* Analyse "x.y" * Analyse "x.y"
*/ */
@@ -3741,6 +3788,7 @@ CHECK_DEEPER:
if (flat_type->type_kind == TYPE_SUBARRAY) if (flat_type->type_kind == TYPE_SUBARRAY)
{ {
// Handle literal "foo".len which is now a subarray. // Handle literal "foo".len which is now a subarray.
sema_expr_flatten_const(context, parent);
if (expr_is_const_string(parent)) if (expr_is_const_string(parent))
{ {
expr_rewrite_const_int(expr, type_isz, parent->const_expr.string.len); expr_rewrite_const_int(expr, type_isz, parent->const_expr.string.len);
@@ -3802,7 +3850,7 @@ CHECK_DEEPER:
} }
if (flat_type->type_kind == TYPE_FAULTTYPE) if (flat_type->type_kind == TYPE_FAULTTYPE)
{ {
if (expr_is_const(current_parent)) if (sema_flattened_expr_is_const(context, current_parent))
{ {
if (current_parent->const_expr.const_kind == CONST_POINTER) if (current_parent->const_expr.const_kind == CONST_POINTER)
{ {
@@ -3821,7 +3869,7 @@ CHECK_DEEPER:
{ {
if (flat_type->type_kind == TYPE_ENUM) if (flat_type->type_kind == TYPE_ENUM)
{ {
if (expr_is_const(current_parent)) if (sema_flattened_expr_is_const(context, current_parent))
{ {
expr_rewrite_to_string(expr, current_parent->const_expr.enum_err_val->name); expr_rewrite_to_string(expr, current_parent->const_expr.enum_err_val->name);
return true; return true;
@@ -6474,7 +6522,7 @@ static inline bool sema_expr_analyse_decl_element(SemaContext *context, Designat
SEMA_ERROR(inner, "Expected an integer index."); SEMA_ERROR(inner, "Expected an integer index.");
return false; return false;
} }
if (!expr_is_const(inner)) if (!sema_flattened_expr_is_const(context, inner))
{ {
SEMA_ERROR(inner, "Expected a constant index."); SEMA_ERROR(inner, "Expected a constant index.");
return false; return false;
@@ -7337,7 +7385,7 @@ static inline bool sema_expr_analyse_retval(SemaContext *c, Expr *expr)
} }
Expr *return_value = c->return_expr; Expr *return_value = c->return_expr;
assert(return_value); assert(return_value);
if (expr_is_const(return_value)) if (sema_flattened_expr_is_const(c, return_value))
{ {
expr_replace(expr, return_value); expr_replace(expr, return_value);
} }
@@ -7576,6 +7624,11 @@ static inline bool sema_cast_rvalue(SemaContext *context, Expr *expr)
SEMA_ERROR(expr, "A macro name must be followed by '('."); SEMA_ERROR(expr, "A macro name must be followed by '('.");
return false; return false;
} }
// We may have kept FOO.x.y as a reference, fold it now if y is not an aggregate.
if (!type_is_abi_aggregate(expr->type) && sema_flattened_expr_is_const(context, expr->access_expr.parent))
{
return sema_expr_fold_to_member(expr, expr->access_expr.parent, expr->access_expr.ref);
}
break; break;
case EXPR_TYPEINFO: case EXPR_TYPEINFO:
SEMA_ERROR(expr, "A type must be followed by either (...) or '.'."); SEMA_ERROR(expr, "A type must be followed by either (...) or '.'.");
@@ -7615,7 +7668,7 @@ bool sema_analyse_ct_expr(SemaContext *context, Expr *expr)
expr->type = type_typeid; expr->type = type_typeid;
} }
if (!sema_cast_rvalue(context, expr)) return false; if (!sema_cast_rvalue(context, expr)) return false;
if (!expr_is_const(expr)) if (!sema_flattened_expr_is_const(context, expr))
{ {
SEMA_ERROR(expr, "Expected a compile time expression."); SEMA_ERROR(expr, "Expected a compile time expression.");
return false; return false;

View File

@@ -86,6 +86,7 @@ bool cast_promote_vararg(Expr *arg);
Type *cast_numeric_arithmetic_promotion(Type *type); Type *cast_numeric_arithmetic_promotion(Type *type);
void cast_to_int_to_max_bit_size(SemaContext *context, Expr *lhs, Expr *rhs, Type *left_type, Type *right_type); void cast_to_int_to_max_bit_size(SemaContext *context, Expr *lhs, Expr *rhs, Type *left_type, Type *right_type);
bool sema_decl_if_cond(SemaContext *context, Decl *decl); bool sema_decl_if_cond(SemaContext *context, Decl *decl);
bool sema_flattened_expr_is_const(SemaContext *context, Expr *expr);
bool sema_analyse_checked(SemaContext *context, Ast *directive, SourceSpan span); bool sema_analyse_checked(SemaContext *context, Ast *directive, SourceSpan span);

View File

@@ -400,7 +400,7 @@ bool type_is_abi_aggregate(Type *type)
return true; return true;
case CT_TYPES: case CT_TYPES:
case TYPE_FLEXIBLE_ARRAY: case TYPE_FLEXIBLE_ARRAY:
UNREACHABLE return false;
} }
UNREACHABLE UNREACHABLE
} }

View File

@@ -1 +1 @@
#define COMPILER_VERSION "0.4.545" #define COMPILER_VERSION "0.4.546"

View File

@@ -0,0 +1,23 @@
// #target: macos-x64
module test;
const FOO = "123";
int[FOO.len] x;
fn void main()
{
int z = x[0];
}
/* #expect: test.ll
@test.FOO = local_unnamed_addr constant %"char[]" { ptr @.str, i64 3 }, align 8
@test.x = local_unnamed_addr global [3 x i32] zeroinitializer, align 4
define void @test.main() #0 {
entry:
%z = alloca i32, align 4
%0 = load i32, ptr @test.x, align 4
store i32 %0, ptr %z, align 4
ret void
}

View File

@@ -0,0 +1,40 @@
// #target: macos-x64
module test;
struct Abc
{
int a;
int b;
}
const Abc X = { 2, 3 };
const int Y = X.b;
const int* Z = &X.b;
fn void main()
{
Abc x = X;
int y = Y;
int* yy = &Y;
int* z = Z;
}
/* #expect: test.ll
@test.X = constant %Abc { i32 2, i32 3 }, align 4
@test.Y = constant i32 3, align 4
@test.Z = local_unnamed_addr constant ptr getelementptr inbounds (%Abc, ptr @test.X, i32 0, i32 1), align 8
define void @test.main() #0 {
entry:
%x = alloca %Abc, align 4
%y = alloca i32, align 4
%yy = alloca ptr, align 8
%z = alloca ptr, align 8
call void @llvm.memcpy.p0.p0.i32(ptr align 4 %x, ptr align 4 @test.X, i32 8, i1 false)
store i32 3, ptr %y, align 4
store ptr @test.Y, ptr %yy, align 8
store ptr getelementptr inbounds (%Abc, ptr @test.X, i32 0, i32 1), ptr %z, align 8
ret void
}