mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Indexing into a constant array / struct now works at compile time. Constants defined by indexing into another constant could fail codegen. Stdlib nolibc code bugs fixed.
This commit is contained in:
@@ -54,6 +54,32 @@ fn List* List.temp_init(&self, usz initial_capacity = 16)
|
|||||||
return self.new_init(initial_capacity, allocator::temp()) @inline;
|
return self.new_init(initial_capacity, allocator::temp()) @inline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize a new list with an array.
|
||||||
|
*
|
||||||
|
* @param [in] values `The values to initialize the list with.`
|
||||||
|
* @require self.size == 0 "The List must be empty"
|
||||||
|
**/
|
||||||
|
fn List* List.new_init_with_array(&self, Type[] values, Allocator allocator = allocator::heap())
|
||||||
|
{
|
||||||
|
self.new_init(values.len, allocator) @inline;
|
||||||
|
self.add_array(values) @inline;
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize a temporary list with an array.
|
||||||
|
*
|
||||||
|
* @param [in] values `The values to initialize the list with.`
|
||||||
|
* @require self.size == 0 "The List must be empty"
|
||||||
|
**/
|
||||||
|
fn List* List.temp_init_with_array(&self, Type[] values)
|
||||||
|
{
|
||||||
|
self.temp_init(values.len) @inline;
|
||||||
|
self.add_array(values) @inline;
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @require self.size == 0 "The List must be empty"
|
* @require self.size == 0 "The List must be empty"
|
||||||
**/
|
**/
|
||||||
@@ -192,6 +218,12 @@ fn Type[] List.array_view(&self)
|
|||||||
return self.entries[:self.size];
|
return self.entries[:self.size];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the values of an array to this list.
|
||||||
|
*
|
||||||
|
* @param [in] array
|
||||||
|
* @ensure self.size >= array.len
|
||||||
|
**/
|
||||||
fn void List.add_array(&self, Type[] array)
|
fn void List.add_array(&self, Type[] array)
|
||||||
{
|
{
|
||||||
if (!array.len) return;
|
if (!array.len) return;
|
||||||
|
|||||||
@@ -384,7 +384,7 @@ File stderr_file;
|
|||||||
|
|
||||||
fn void putchar(char c) @inline
|
fn void putchar(char c) @inline
|
||||||
{
|
{
|
||||||
(void)stdout_file.putc(c);
|
(void)stdout_file.write_byte(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn File* stdout()
|
fn File* stdout()
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ fn Path! native_temp_directory(Allocator allocator = allocator::heap()) @if(env:
|
|||||||
}
|
}
|
||||||
|
|
||||||
module std::io::os @if(env::NO_LIBC);
|
module std::io::os @if(env::NO_LIBC);
|
||||||
|
import std::io::path;
|
||||||
|
|
||||||
macro Path! native_temp_directory(Allocator allocator = allocator::heap())
|
macro Path! native_temp_directory(Allocator allocator = allocator::heap())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ fn double __tan(double x, double y, int odd) @extern("__tan") @weak @nostrip
|
|||||||
w = x + r;
|
w = x + r;
|
||||||
if (big)
|
if (big)
|
||||||
{
|
{
|
||||||
s = 1 - 2 * odd;
|
s = (double)(1 - 2 * odd);
|
||||||
v = s - 2.0 * (x + (r - w*w/(w + s)));
|
v = s - 2.0 * (x + (r - w*w/(w + s)));
|
||||||
return sign ? -v : v;
|
return sign ? -v : v;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ fn int __rem_pio2f(float x, double *y)
|
|||||||
if (ix >= 0x7f800000)
|
if (ix >= 0x7f800000)
|
||||||
{
|
{
|
||||||
// x is inf or NaN */
|
// x is inf or NaN */
|
||||||
*y = x-x;
|
*y = x - (double)x;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* scale x into [2^23, 2^24-1] */
|
/* scale x into [2^23, 2^24-1] */
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
- Macro `$case` statements now pick the first match and does not evaluate the rest.
|
- Macro `$case` statements now pick the first match and does not evaluate the rest.
|
||||||
- `manifest.json` is now checked for incorrect keys.
|
- `manifest.json` is now checked for incorrect keys.
|
||||||
- Added `--list-manifest-properties` to list the available properties in `manifest.json`.
|
- Added `--list-manifest-properties` to list the available properties in `manifest.json`.
|
||||||
|
- Indexing into a constant array / struct now works at compile time.
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
- Error with unsigned compare in `@ensure` when early returning 0 #1207.
|
- Error with unsigned compare in `@ensure` when early returning 0 #1207.
|
||||||
@@ -45,6 +46,8 @@
|
|||||||
- Bitstructs in structs would not be correctly be handled in some cases.
|
- Bitstructs in structs would not be correctly be handled in some cases.
|
||||||
- Fix problem where a $$FUNC would return "<GLOBAL>" when evaluated for a static in a function #1236.
|
- Fix problem where a $$FUNC would return "<GLOBAL>" when evaluated for a static in a function #1236.
|
||||||
- `ordinal` is no longer a valid associated value name for enums.
|
- `ordinal` is no longer a valid associated value name for enums.
|
||||||
|
- Constants defined by indexing into another constant could fail codegen.
|
||||||
|
- Stdlib nolibc code bugs fixed.
|
||||||
|
|
||||||
### Stdlib changes
|
### Stdlib changes
|
||||||
- Added `remove_first_item` `remove_last_item` and `remove_item` as aliases for the `match` functions.
|
- Added `remove_first_item` `remove_last_item` and `remove_item` as aliases for the `match` functions.
|
||||||
@@ -55,6 +58,7 @@
|
|||||||
- Updated sorting API.
|
- Updated sorting API.
|
||||||
- Insertion sort and counting sort added.
|
- Insertion sort and counting sort added.
|
||||||
- Added missing `mem` and `mem::allocator` functions for aligned allocations.
|
- Added missing `mem` and `mem::allocator` functions for aligned allocations.
|
||||||
|
- Added `new_init_with_array` and `temp_init_with_array` for List.
|
||||||
|
|
||||||
## 0.6.0 Change list
|
## 0.6.0 Change list
|
||||||
|
|
||||||
|
|||||||
@@ -2252,6 +2252,7 @@ bool expr_is_simple(Expr *expr, bool to_float);
|
|||||||
bool expr_is_pure(Expr *expr);
|
bool expr_is_pure(Expr *expr);
|
||||||
bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind);
|
bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind);
|
||||||
bool expr_is_compile_time(Expr *ast);
|
bool expr_is_compile_time(Expr *ast);
|
||||||
|
bool range_is_const(Range *range);
|
||||||
Expr *expr_generate_decl(Decl *decl, Expr *assign);
|
Expr *expr_generate_decl(Decl *decl, Expr *assign);
|
||||||
void expr_insert_addr(Expr *original);
|
void expr_insert_addr(Expr *original);
|
||||||
void expr_rewrite_insert_deref(Expr *original);
|
void expr_rewrite_insert_deref(Expr *original);
|
||||||
@@ -2347,6 +2348,7 @@ bool sema_analyse_cond_expr(SemaContext *context, Expr *expr, CondResult *result
|
|||||||
bool sema_analyse_expr_rhs(SemaContext *context, Type *to, Expr *expr, bool allow_optional, bool *no_match_ref);
|
bool sema_analyse_expr_rhs(SemaContext *context, Type *to, Expr *expr, bool allow_optional, bool *no_match_ref);
|
||||||
ArrayIndex sema_get_initializer_const_array_size(SemaContext *context, Expr *initializer, bool *may_be_array, bool *is_const_size);
|
ArrayIndex sema_get_initializer_const_array_size(SemaContext *context, Expr *initializer, bool *may_be_array, bool *is_const_size);
|
||||||
bool sema_analyse_expr(SemaContext *context, Expr *expr);
|
bool sema_analyse_expr(SemaContext *context, Expr *expr);
|
||||||
|
bool sema_cast_const(Expr *expr);
|
||||||
|
|
||||||
bool sema_expr_check_discard(SemaContext *context, Expr *expr);
|
bool sema_expr_check_discard(SemaContext *context, Expr *expr);
|
||||||
bool sema_analyse_inferred_expr(SemaContext *context, Type *to, Expr *expr);
|
bool sema_analyse_inferred_expr(SemaContext *context, Type *to, Expr *expr);
|
||||||
|
|||||||
@@ -268,7 +268,7 @@ bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind)
|
|||||||
if (expr->slice_expr.end && !exprid_is_constant_eval(expr->slice_expr.end, CONSTANT_EVAL_FOLDABLE)) return false;
|
if (expr->slice_expr.end && !exprid_is_constant_eval(expr->slice_expr.end, CONSTANT_EVAL_FOLDABLE)) return false;
|
||||||
return exprid_is_constant_eval(expr->slice_expr.expr, eval_kind);*/
|
return exprid_is_constant_eval(expr->slice_expr.expr, eval_kind);*/
|
||||||
case EXPR_SUBSCRIPT:
|
case EXPR_SUBSCRIPT:
|
||||||
if (!exprid_is_constant_eval(expr->subscript_expr.range.start, eval_kind)) return false;
|
if (!range_is_const(&expr->subscript_expr.range)) return false;
|
||||||
expr = exprptr(expr->subscript_expr.expr);
|
expr = exprptr(expr->subscript_expr.expr);
|
||||||
goto RETRY;
|
goto RETRY;
|
||||||
case EXPR_SUBSCRIPT_ADDR:
|
case EXPR_SUBSCRIPT_ADDR:
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ static bool sema_check_builtin_args_const(SemaContext *context, Expr **args, siz
|
|||||||
{
|
{
|
||||||
for (size_t i = 0; i < arg_len; i++)
|
for (size_t i = 0; i < arg_len; i++)
|
||||||
{
|
{
|
||||||
if (!expr_is_const(args[i])) RETURN_SEMA_ERROR(args[i], "Expected a compile time constant value for this argument.");
|
if (!sema_cast_const(args[i])) RETURN_SEMA_ERROR(args[i], "Expected a compile time constant value for this argument.");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -238,11 +238,9 @@ static bool sema_expr_analyse_compare_exchange(SemaContext *context, Expr *expr)
|
|||||||
for (int i = 3; i < 5; i++)
|
for (int i = 3; i < 5; i++)
|
||||||
{
|
{
|
||||||
if (!sema_analyse_expr_rhs(context, type_bool, args[i], false, NULL)) return false;
|
if (!sema_analyse_expr_rhs(context, type_bool, args[i], false, NULL)) return false;
|
||||||
if (!expr_is_const(args[i]))
|
if (!sema_cast_const(args[i]))
|
||||||
{
|
{
|
||||||
SEMA_ERROR(args[i], "Expected a constant boolean value.");
|
RETURN_SEMA_ERROR(args[i], "Expected a constant boolean value.");}
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for (int i = 5; i < 7; i++)
|
for (int i = 5; i < 7; i++)
|
||||||
{
|
{
|
||||||
@@ -579,7 +577,7 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr)
|
|||||||
{
|
{
|
||||||
RETURN_SEMA_ERROR(args[2], "Expected a 'double', but was %s.", type_quoted_error_string(args[2]->type));
|
RETURN_SEMA_ERROR(args[2], "Expected a 'double', but was %s.", type_quoted_error_string(args[2]->type));
|
||||||
}
|
}
|
||||||
if (!expr_is_const(args[2]))
|
if (!sema_cast_const(args[2]))
|
||||||
{
|
{
|
||||||
RETURN_SEMA_ERROR(args[2], "This value must be a constant.");
|
RETURN_SEMA_ERROR(args[2], "This value must be a constant.");
|
||||||
}
|
}
|
||||||
@@ -640,7 +638,7 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr)
|
|||||||
if (!sema_check_builtin_args(context, args, (BuiltinArg[]) {BA_POINTER, BA_INTEGER, BA_INTEGER}, 3)) return false;
|
if (!sema_check_builtin_args(context, args, (BuiltinArg[]) {BA_POINTER, BA_INTEGER, BA_INTEGER}, 3)) return false;
|
||||||
for (unsigned i = 1; i < 3; i++)
|
for (unsigned i = 1; i < 3; i++)
|
||||||
{
|
{
|
||||||
if (!expr_is_const(args[i])) RETURN_SEMA_ERROR(args[i], "A constant value is required.");
|
if (!sema_cast_const(args[i])) RETURN_SEMA_ERROR(args[i], "A constant value is required.");
|
||||||
if (!cast_implicit(context, args[i], type_int)) return false;
|
if (!cast_implicit(context, args[i], type_int)) return false;
|
||||||
}
|
}
|
||||||
if (!expr_in_int_range(args[1], 0, 1))
|
if (!expr_in_int_range(args[1], 0, 1))
|
||||||
@@ -815,8 +813,8 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr)
|
|||||||
if (!sema_check_builtin_args(context, args, (BuiltinArg[]) {BA_POINTER, BA_BOOL, BA_INTEGER}, 3)) return false;
|
if (!sema_check_builtin_args(context, args, (BuiltinArg[]) {BA_POINTER, BA_BOOL, BA_INTEGER}, 3)) return false;
|
||||||
Type *original = type_flatten(args[0]->type);
|
Type *original = type_flatten(args[0]->type);
|
||||||
if (original == type_voidptr) RETURN_SEMA_ERROR(args[0], "Expected a typed pointer.");
|
if (original == type_voidptr) RETURN_SEMA_ERROR(args[0], "Expected a typed pointer.");
|
||||||
if (!expr_is_const(args[1])) RETURN_SEMA_ERROR(args[1], "'is_volatile' must be a compile time constant.");
|
if (!sema_cast_const(args[1])) RETURN_SEMA_ERROR(args[1], "'is_volatile' must be a compile time constant.");
|
||||||
if (!expr_is_const(args[2])) RETURN_SEMA_ERROR(args[2], "Ordering must be a compile time constant.");
|
if (!sema_cast_const(args[2])) RETURN_SEMA_ERROR(args[2], "Ordering must be a compile time constant.");
|
||||||
if (!is_valid_atomicity(context, args[2])) return false;
|
if (!is_valid_atomicity(context, args[2])) return false;
|
||||||
switch (args[2]->const_expr.ixx.i.low)
|
switch (args[2]->const_expr.ixx.i.low)
|
||||||
{
|
{
|
||||||
@@ -892,8 +890,8 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr)
|
|||||||
}
|
}
|
||||||
if (!cast_implicit(context, args[1], original->pointer)) return false;
|
if (!cast_implicit(context, args[1], original->pointer)) return false;
|
||||||
}
|
}
|
||||||
if (!expr_is_const(args[2])) RETURN_SEMA_ERROR(args[2], "'is_volatile' must be a compile time constant.");
|
if (!sema_cast_const(args[2])) RETURN_SEMA_ERROR(args[2], "'is_volatile' must be a compile time constant.");
|
||||||
if (!expr_is_const(args[3])) RETURN_SEMA_ERROR(args[3], "Ordering must be a compile time constant.");
|
if (!sema_cast_const(args[3])) RETURN_SEMA_ERROR(args[3], "Ordering must be a compile time constant.");
|
||||||
if (!is_valid_atomicity(context, args[3])) return false;
|
if (!is_valid_atomicity(context, args[3])) return false;
|
||||||
switch (args[3]->const_expr.ixx.i.low)
|
switch (args[3]->const_expr.ixx.i.low)
|
||||||
{
|
{
|
||||||
@@ -916,8 +914,8 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr)
|
|||||||
{
|
{
|
||||||
if (!cast_implicit(context, args[1], original->pointer)) return false;
|
if (!cast_implicit(context, args[1], original->pointer)) return false;
|
||||||
}
|
}
|
||||||
if (!expr_is_const(args[2])) RETURN_SEMA_ERROR(args[2], "'is_volatile' must be a compile time constant.");
|
if (!sema_cast_const(args[2])) RETURN_SEMA_ERROR(args[2], "'is_volatile' must be a compile time constant.");
|
||||||
if (!expr_is_const(args[3])) RETURN_SEMA_ERROR(args[3], "Ordering must be a compile time constant.");
|
if (!sema_cast_const(args[3])) RETURN_SEMA_ERROR(args[3], "Ordering must be a compile time constant.");
|
||||||
if (!is_valid_atomicity(context, args[3])) return false;
|
if (!is_valid_atomicity(context, args[3])) return false;
|
||||||
switch (args[3]->const_expr.ixx.i.low)
|
switch (args[3]->const_expr.ixx.i.low)
|
||||||
{
|
{
|
||||||
@@ -939,8 +937,8 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr)
|
|||||||
}
|
}
|
||||||
Type *val = type_flatten(args[1]->type);
|
Type *val = type_flatten(args[1]->type);
|
||||||
if (!type_is_atomic(val)) RETURN_SEMA_ERROR(args[1], "%s exceeds pointer size.", val);
|
if (!type_is_atomic(val)) RETURN_SEMA_ERROR(args[1], "%s exceeds pointer size.", val);
|
||||||
if (!expr_is_const(args[2])) RETURN_SEMA_ERROR(args[2], "'is_volatile' must be a compile time constant.");
|
if (!sema_cast_const(args[2])) RETURN_SEMA_ERROR(args[2], "'is_volatile' must be a compile time constant.");
|
||||||
if (!expr_is_const(args[3])) RETURN_SEMA_ERROR(args[3], "Ordering must be a compile time constant.");
|
if (!sema_cast_const(args[3])) RETURN_SEMA_ERROR(args[3], "Ordering must be a compile time constant.");
|
||||||
if (!is_valid_atomicity(context, args[3])) return false;
|
if (!is_valid_atomicity(context, args[3])) return false;
|
||||||
switch (args[3]->const_expr.ixx.i.low)
|
switch (args[3]->const_expr.ixx.i.low)
|
||||||
{
|
{
|
||||||
@@ -963,8 +961,8 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr)
|
|||||||
{
|
{
|
||||||
if (!cast_implicit(context, args[1], original->pointer)) return false;
|
if (!cast_implicit(context, args[1], original->pointer)) return false;
|
||||||
}
|
}
|
||||||
if (!expr_is_const(args[2])) RETURN_SEMA_ERROR(args[2], "'is_volatile' must be a compile time constant.");
|
if (!sema_cast_const(args[2])) RETURN_SEMA_ERROR(args[2], "'is_volatile' must be a compile time constant.");
|
||||||
if (!expr_is_const(args[3])) RETURN_SEMA_ERROR(args[3], "Ordering must be a compile time constant.");
|
if (!sema_cast_const(args[3])) RETURN_SEMA_ERROR(args[3], "Ordering must be a compile time constant.");
|
||||||
if (!is_valid_atomicity(context, args[3])) return false;
|
if (!is_valid_atomicity(context, args[3])) return false;
|
||||||
switch (args[3]->const_expr.ixx.i.low)
|
switch (args[3]->const_expr.ixx.i.low)
|
||||||
{
|
{
|
||||||
@@ -985,8 +983,8 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr)
|
|||||||
{
|
{
|
||||||
if (!cast_implicit(context, args[1], original->pointer)) return false;
|
if (!cast_implicit(context, args[1], original->pointer)) return false;
|
||||||
}
|
}
|
||||||
if (!expr_is_const(args[2])) RETURN_SEMA_ERROR(args[2], "'is_volatile' must be a compile time constant.");
|
if (!sema_cast_const(args[2])) RETURN_SEMA_ERROR(args[2], "'is_volatile' must be a compile time constant.");
|
||||||
if (!expr_is_const(args[3])) RETURN_SEMA_ERROR(args[3], "Ordering must be a compile time constant.");
|
if (!sema_cast_const(args[3])) RETURN_SEMA_ERROR(args[3], "Ordering must be a compile time constant.");
|
||||||
if (!is_valid_atomicity(context, args[3])) return false;
|
if (!is_valid_atomicity(context, args[3])) return false;
|
||||||
switch (args[3]->const_expr.ixx.i.low)
|
switch (args[3]->const_expr.ixx.i.low)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -710,7 +710,7 @@ static bool rule_int_to_ptr(CastContext *cc, bool is_explicit, bool is_silent)
|
|||||||
{
|
{
|
||||||
// Handle const:
|
// Handle const:
|
||||||
Expr *expr = cc->expr;
|
Expr *expr = cc->expr;
|
||||||
if (expr_is_const(expr))
|
if (sema_cast_const(expr))
|
||||||
{
|
{
|
||||||
if (!is_explicit) return sema_cast_error(cc, true, is_silent);
|
if (!is_explicit) return sema_cast_error(cc, true, is_silent);
|
||||||
|
|
||||||
@@ -1123,7 +1123,7 @@ static bool rule_widen_narrow(CastContext *cc, bool is_explicit, bool is_silent)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If const, check in range.
|
// If const, check in range.
|
||||||
if (expr_is_const(expr) && expr_const_will_overflow(&expr->const_expr, cc->to->type_kind))
|
if (sema_cast_const(expr) && expr_const_will_overflow(&expr->const_expr, cc->to->type_kind))
|
||||||
{
|
{
|
||||||
if (!is_silent)
|
if (!is_silent)
|
||||||
{
|
{
|
||||||
@@ -1186,7 +1186,7 @@ static bool rule_to_distinct(CastContext *cc, bool is_explicit, bool is_silent)
|
|||||||
assert(from_type == from_type->canonical);
|
assert(from_type == from_type->canonical);
|
||||||
Type *flat = type_flatten(cc->to);
|
Type *flat = type_flatten(cc->to);
|
||||||
ConvGroup flat_group = type_to_group(flat);
|
ConvGroup flat_group = type_to_group(flat);
|
||||||
if (expr_is_const(cc->expr))
|
if (sema_cast_const(cc->expr))
|
||||||
{
|
{
|
||||||
cc->to = flat;
|
cc->to = flat;
|
||||||
cc->to_group = flat_group;
|
cc->to_group = flat_group;
|
||||||
@@ -1280,7 +1280,7 @@ static bool rule_int_to_enum(CastContext *cc, bool is_explicit, bool is_silent)
|
|||||||
{
|
{
|
||||||
if (!is_explicit) return sema_cast_error(cc, true, is_silent);
|
if (!is_explicit) return sema_cast_error(cc, true, is_silent);
|
||||||
|
|
||||||
if (!expr_is_const(cc->expr)) return true;
|
if (!sema_cast_const(cc->expr)) return true;
|
||||||
|
|
||||||
Decl *enum_decl = cc->to->decl;
|
Decl *enum_decl = cc->to->decl;
|
||||||
// Check that the type is within limits.
|
// Check that the type is within limits.
|
||||||
@@ -1367,7 +1367,7 @@ static void cast_retype(SemaContext *context, Expr *expr, Type *to_type) { expr-
|
|||||||
*/
|
*/
|
||||||
INLINE bool insert_runtime_cast_unless_const(Expr *expr, CastKind kind, Type *type)
|
INLINE bool insert_runtime_cast_unless_const(Expr *expr, CastKind kind, Type *type)
|
||||||
{
|
{
|
||||||
if (expr_is_const(expr) && expr->const_expr.const_kind != CONST_TYPEID) return false;
|
if (sema_cast_const(expr) && expr->const_expr.const_kind != CONST_TYPEID) return false;
|
||||||
return insert_runtime_cast(expr, kind, type);
|
return insert_runtime_cast(expr, kind, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1605,7 +1605,7 @@ static void cast_enum_to_int(SemaContext *context, Expr* expr, Type *to_type)
|
|||||||
{
|
{
|
||||||
assert(type_flatten(expr->type)->type_kind == TYPE_ENUM);
|
assert(type_flatten(expr->type)->type_kind == TYPE_ENUM);
|
||||||
Type *underlying_type = type_base(expr->type);
|
Type *underlying_type = type_base(expr->type);
|
||||||
if (expr_is_const(expr))
|
if (sema_cast_const(expr))
|
||||||
{
|
{
|
||||||
assert(expr->const_expr.const_kind == CONST_ENUM);
|
assert(expr->const_expr.const_kind == CONST_ENUM);
|
||||||
expr_rewrite_const_int(expr, underlying_type, expr->const_expr.enum_err_val->enum_constant.ordinal);
|
expr_rewrite_const_int(expr, underlying_type, expr->const_expr.enum_err_val->enum_constant.ordinal);
|
||||||
@@ -1638,7 +1638,7 @@ static void cast_vec_to_arr(SemaContext *context, Expr *expr, Type *to_type)
|
|||||||
*/
|
*/
|
||||||
static void cast_vec_to_vec(SemaContext *context, Expr *expr, Type *to_type)
|
static void cast_vec_to_vec(SemaContext *context, Expr *expr, Type *to_type)
|
||||||
{
|
{
|
||||||
if (!expr_is_const(expr))
|
if (!sema_cast_const(expr))
|
||||||
{
|
{
|
||||||
// Extract indexed types.
|
// Extract indexed types.
|
||||||
Type *from_type = type_flatten(expr->type);
|
Type *from_type = type_flatten(expr->type);
|
||||||
@@ -1781,7 +1781,7 @@ static void cast_int_to_ptr(SemaContext *context, Expr *expr, Type *type)
|
|||||||
assert(type_bit_size(type_uptr) <= 64 && "For > 64 bit pointers, this code needs updating.");
|
assert(type_bit_size(type_uptr) <= 64 && "For > 64 bit pointers, this code needs updating.");
|
||||||
|
|
||||||
// Handle const:
|
// Handle const:
|
||||||
if (expr_is_const(expr))
|
if (sema_cast_const(expr))
|
||||||
{
|
{
|
||||||
expr->type = type;
|
expr->type = type;
|
||||||
expr->const_expr.ptr = expr->const_expr.ixx.i.low;
|
expr->const_expr.ptr = expr->const_expr.ixx.i.low;
|
||||||
@@ -1905,7 +1905,7 @@ static void cast_slice_to_slice(SemaContext *context, Expr *expr, Type *to_type)
|
|||||||
{
|
{
|
||||||
Type *to_type_base = type_flatten(type_flatten(to_type)->array.base);
|
Type *to_type_base = type_flatten(type_flatten(to_type)->array.base);
|
||||||
Type *from_type_base = type_flatten(type_flatten(expr->type)->array.base);
|
Type *from_type_base = type_flatten(type_flatten(expr->type)->array.base);
|
||||||
if (expr_is_const(expr) || to_type_base == from_type_base || (type_is_pointer(to_type_base) && type_is_pointer(from_type_base)))
|
if (sema_cast_const(expr) || to_type_base == from_type_base || (type_is_pointer(to_type_base) && type_is_pointer(from_type_base)))
|
||||||
{
|
{
|
||||||
expr->type = to_type;
|
expr->type = to_type;
|
||||||
return;
|
return;
|
||||||
@@ -1915,7 +1915,7 @@ static void cast_slice_to_slice(SemaContext *context, Expr *expr, Type *to_type)
|
|||||||
|
|
||||||
static void cast_slice_to_vecarr(SemaContext *context, Expr *expr, Type *to_type)
|
static void cast_slice_to_vecarr(SemaContext *context, Expr *expr, Type *to_type)
|
||||||
{
|
{
|
||||||
if (!expr_is_const(expr))
|
if (!sema_cast_const(expr))
|
||||||
{
|
{
|
||||||
switch (expr->expr_kind)
|
switch (expr->expr_kind)
|
||||||
{
|
{
|
||||||
@@ -1973,7 +1973,7 @@ static void cast_arr_to_vec(SemaContext *context, Expr *expr, Type *to_type)
|
|||||||
Type *index_vec = type_flatten(type_get_indexed_type(to_type));
|
Type *index_vec = type_flatten(type_get_indexed_type(to_type));
|
||||||
Type *index_arr = type_flatten(type_get_indexed_type(expr->type));
|
Type *index_arr = type_flatten(type_get_indexed_type(expr->type));
|
||||||
Type *to_temp = index_vec == index_arr ? to_type : type_get_vector(index_arr, type_flatten(expr->type)->array.len);
|
Type *to_temp = index_vec == index_arr ? to_type : type_get_vector(index_arr, type_flatten(expr->type)->array.len);
|
||||||
if (expr_is_const(expr))
|
if (sema_cast_const(expr))
|
||||||
{
|
{
|
||||||
// For the array -> vector this is always a simple rewrite of type.
|
// For the array -> vector this is always a simple rewrite of type.
|
||||||
assert(expr->const_expr.const_kind == CONST_INITIALIZER);
|
assert(expr->const_expr.const_kind == CONST_INITIALIZER);
|
||||||
|
|||||||
@@ -798,7 +798,7 @@ static inline bool sema_analyse_bitstruct_member(SemaContext *context, Decl *par
|
|||||||
if (!sema_analyse_expr(context, start)) return false;
|
if (!sema_analyse_expr(context, start)) return false;
|
||||||
|
|
||||||
// Check for negative, non integer or non const values.
|
// Check for negative, non integer or non const values.
|
||||||
if (!expr_is_const(start) || !type_is_integer(start->type) || int_is_neg(start->const_expr.ixx))
|
if (!sema_cast_const(start) || !type_is_integer(start->type) || int_is_neg(start->const_expr.ixx))
|
||||||
{
|
{
|
||||||
SEMA_ERROR(start, "This must be a constant non-negative integer value.");
|
SEMA_ERROR(start, "This must be a constant non-negative integer value.");
|
||||||
return false;
|
return false;
|
||||||
@@ -819,7 +819,7 @@ static inline bool sema_analyse_bitstruct_member(SemaContext *context, Decl *par
|
|||||||
{
|
{
|
||||||
// Analyse the end
|
// Analyse the end
|
||||||
if (!sema_analyse_expr(context, start)) return false;
|
if (!sema_analyse_expr(context, start)) return false;
|
||||||
if (!expr_is_const(end) || !type_is_integer(end->type) || int_is_neg(end->const_expr.ixx))
|
if (!sema_cast_const(end) || !type_is_integer(end->type) || int_is_neg(end->const_expr.ixx))
|
||||||
{
|
{
|
||||||
SEMA_ERROR(end, "This must be a constant non-negative integer value.");
|
SEMA_ERROR(end, "This must be a constant non-negative integer value.");
|
||||||
return false;
|
return false;
|
||||||
@@ -2522,7 +2522,7 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr,
|
|||||||
case ATTRIBUTE_IF:
|
case ATTRIBUTE_IF:
|
||||||
if (!expr) RETURN_SEMA_ERROR(attr, "'@if' requires a boolean argument.");
|
if (!expr) RETURN_SEMA_ERROR(attr, "'@if' requires a boolean argument.");
|
||||||
if (!sema_analyse_expr(context, expr)) return false;
|
if (!sema_analyse_expr(context, expr)) return false;
|
||||||
if (expr->type->canonical != type_bool || !expr_is_const(expr))
|
if (expr->type->canonical != type_bool || !sema_cast_const(expr))
|
||||||
{
|
{
|
||||||
RETURN_SEMA_ERROR(expr, "Expected a boolean compile time constant value.");
|
RETURN_SEMA_ERROR(expr, "Expected a boolean compile time constant value.");
|
||||||
}
|
}
|
||||||
@@ -3626,6 +3626,7 @@ bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local)
|
|||||||
if (!type_info)
|
if (!type_info)
|
||||||
{
|
{
|
||||||
if (!sema_analyse_expr(context, init_expr)) return decl_poison(decl);
|
if (!sema_analyse_expr(context, init_expr)) return decl_poison(decl);
|
||||||
|
if (global_level_var || !type_is_abi_aggregate(init_expr->type)) sema_cast_const(init_expr);
|
||||||
if (global_level_var && !expr_is_constant_eval(init_expr, CONSTANT_EVAL_GLOBAL_INIT))
|
if (global_level_var && !expr_is_constant_eval(init_expr, CONSTANT_EVAL_GLOBAL_INIT))
|
||||||
{
|
{
|
||||||
SEMA_ERROR(init_expr, "This expression cannot be evaluated at compile time.");
|
SEMA_ERROR(init_expr, "This expression cannot be evaluated at compile time.");
|
||||||
@@ -3731,6 +3732,7 @@ bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local)
|
|||||||
SEMA_ERROR(init_expr, "The expression must be a constant value.");
|
SEMA_ERROR(init_expr, "The expression must be a constant value.");
|
||||||
return decl_poison(decl);
|
return decl_poison(decl);
|
||||||
}
|
}
|
||||||
|
if (global_level_var || !type_is_abi_aggregate(init_expr->type)) sema_cast_const(init_expr);
|
||||||
if (expr_is_const(init_expr))
|
if (expr_is_const(init_expr))
|
||||||
{
|
{
|
||||||
init_expr->const_expr.is_hex = false;
|
init_expr->const_expr.is_hex = false;
|
||||||
|
|||||||
@@ -192,7 +192,8 @@ static inline bool sema_cast_rvalue(SemaContext *context, Expr *expr);
|
|||||||
static inline bool sema_expr_analyse_type_access(SemaContext *context, Expr *expr, Type *parent_type, bool was_group, Expr *identifier, bool *missing_ref);
|
static inline bool sema_expr_analyse_type_access(SemaContext *context, Expr *expr, Type *parent_type, bool was_group, Expr *identifier, bool *missing_ref);
|
||||||
static inline bool sema_expr_analyse_member_access(SemaContext *context, Expr *expr, Expr *parent, bool was_group, Expr *identifier, bool *missing_ref);
|
static inline bool sema_expr_analyse_member_access(SemaContext *context, Expr *expr, Expr *parent, bool was_group, Expr *identifier, bool *missing_ref);
|
||||||
static inline bool sema_expr_fold_to_member(Expr *expr, Expr *parent, Decl *member);
|
static inline bool sema_expr_fold_to_member(Expr *expr, Expr *parent, Decl *member);
|
||||||
static inline void sema_expr_flatten_const(SemaContext *context, Expr *expr);
|
static inline bool sema_expr_fold_to_index(Expr *expr, Expr *parent, Range range);
|
||||||
|
static inline void sema_expr_flatten_const_ident(Expr *expr);
|
||||||
|
|
||||||
static inline bool sema_analyse_maybe_dead_expr(SemaContext *, Expr *expr, bool is_dead);
|
static inline bool sema_analyse_maybe_dead_expr(SemaContext *, Expr *expr, bool is_dead);
|
||||||
|
|
||||||
@@ -200,7 +201,7 @@ static inline bool sema_analyse_maybe_dead_expr(SemaContext *, Expr *expr, bool
|
|||||||
|
|
||||||
static inline bool sema_constant_fold_ops(Expr *expr)
|
static inline bool sema_constant_fold_ops(Expr *expr)
|
||||||
{
|
{
|
||||||
if (!expr_is_const(expr)) return false;
|
if (!sema_cast_const(expr)) return false;
|
||||||
switch (expr->const_expr.const_kind)
|
switch (expr->const_expr.const_kind)
|
||||||
{
|
{
|
||||||
case CONST_INTEGER:
|
case CONST_INTEGER:
|
||||||
@@ -304,7 +305,7 @@ Expr *sema_expr_analyse_ct_arg_index(SemaContext *context, Expr *index_expr, uns
|
|||||||
if (report_error) SEMA_ERROR(index_expr, "Expected the argument index here, but found a value of type %s.", type_quoted_error_string(index_expr->type));
|
if (report_error) SEMA_ERROR(index_expr, "Expected the argument index here, but found a value of type %s.", type_quoted_error_string(index_expr->type));
|
||||||
return poisoned_expr;
|
return poisoned_expr;
|
||||||
}
|
}
|
||||||
if (!expr_is_const(index_expr))
|
if (!sema_cast_const(index_expr))
|
||||||
{
|
{
|
||||||
if (report_error) SEMA_ERROR(index_expr, "Vararg functions need a constant argument, but this is a runtime value.");
|
if (report_error) SEMA_ERROR(index_expr, "Vararg functions need a constant argument, but this is a runtime value.");
|
||||||
return poisoned_expr;
|
return poisoned_expr;
|
||||||
@@ -1423,7 +1424,7 @@ INLINE bool sema_call_expand_arguments(SemaContext *context, CalledDecl *callee,
|
|||||||
RETURN_NOTE_FUNC_DEFINITION;
|
RETURN_NOTE_FUNC_DEFINITION;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (expr_is_const(arg))
|
if (sema_cast_const(arg))
|
||||||
{
|
{
|
||||||
switch (param->var.kind)
|
switch (param->var.kind)
|
||||||
{
|
{
|
||||||
@@ -2048,11 +2049,11 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s
|
|||||||
if (no_match_ref) goto NO_MATCH_REF;
|
if (no_match_ref) goto NO_MATCH_REF;
|
||||||
RETURN_SEMA_ERROR(call_expr, "Too many parameters for the macro body, expected %d.", expected_body_params);
|
RETURN_SEMA_ERROR(call_expr, "Too many parameters for the macro body, expected %d.", expected_body_params);
|
||||||
}
|
}
|
||||||
for (unsigned i = 0; i < expected_body_params; i++)
|
for (unsigned j = 0; j < expected_body_params; j++)
|
||||||
{
|
{
|
||||||
Decl *body_param = macro_body_params[i];
|
Decl *body_param = macro_body_params[j];
|
||||||
assert(body_param->resolve_status == RESOLVE_DONE);
|
assert(body_param->resolve_status == RESOLVE_DONE);
|
||||||
Decl *body_arg = body_params[i];
|
Decl *body_arg = body_params[j];
|
||||||
VarDeclKind kind_of_expected = body_param->var.kind;
|
VarDeclKind kind_of_expected = body_param->var.kind;
|
||||||
if (kind_of_expected != body_arg->var.kind)
|
if (kind_of_expected != body_arg->var.kind)
|
||||||
{
|
{
|
||||||
@@ -2543,7 +2544,7 @@ static inline bool sema_expr_analyse_call(SemaContext *context, Expr *expr, bool
|
|||||||
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)
|
||||||
{
|
{
|
||||||
assert(type == type->canonical);
|
assert(type == type->canonical);
|
||||||
if (!expr_is_const(len_expr)) return true;
|
if (!sema_cast_const(len_expr)) return true;
|
||||||
|
|
||||||
Int const_len = len_expr->const_expr.ixx;
|
Int const_len = len_expr->const_expr.ixx;
|
||||||
if (!int_fits(const_len, TYPE_I64))
|
if (!int_fits(const_len, TYPE_I64))
|
||||||
@@ -2601,7 +2602,7 @@ static bool sema_slice_len_is_in_range(SemaContext *context, Type *type, Expr *l
|
|||||||
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)
|
||||||
{
|
{
|
||||||
assert(type == type->canonical);
|
assert(type == type->canonical);
|
||||||
if (!expr_is_const(index_expr)) return true;
|
if (!sema_cast_const(index_expr)) return true;
|
||||||
|
|
||||||
Int index = index_expr->const_expr.ixx;
|
Int index = index_expr->const_expr.ixx;
|
||||||
if (!int_fits(index, TYPE_I64))
|
if (!int_fits(index, TYPE_I64))
|
||||||
@@ -2929,10 +2930,10 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (sema_flattened_expr_is_const(context, index))
|
if (sema_cast_const(index))
|
||||||
{
|
{
|
||||||
assert(expr_is_const_int(index));
|
assert(expr_is_const_int(index));
|
||||||
sema_expr_flatten_const(context, current_expr);
|
sema_expr_flatten_const_ident(current_expr);
|
||||||
bool is_const_initializer = expr_is_const_initializer(current_expr);
|
bool is_const_initializer = expr_is_const_initializer(current_expr);
|
||||||
if (is_const_initializer || expr_is_const_string(current_expr) || expr_is_const_bytes(current_expr))
|
if (is_const_initializer || expr_is_const_string(current_expr) || expr_is_const_bytes(current_expr))
|
||||||
{
|
{
|
||||||
@@ -2992,7 +2993,7 @@ static inline bool sema_expr_analyse_pointer_offset(SemaContext *context, Expr *
|
|||||||
bool is_optional = IS_OPTIONAL(pointer) || IS_OPTIONAL(offset);
|
bool is_optional = IS_OPTIONAL(pointer) || IS_OPTIONAL(offset);
|
||||||
|
|
||||||
// 4. Possibly constant fold
|
// 4. Possibly constant fold
|
||||||
if (!vec_len && expr_is_const(pointer) && expr_is_const(offset))
|
if (!vec_len && sema_cast_const(pointer) && sema_cast_const(offset))
|
||||||
{
|
{
|
||||||
assert(!is_optional);
|
assert(!is_optional);
|
||||||
Int mul = { .i.low = type_size(type_flatten(pointer->type)->pointer), .type = offset->const_expr.ixx.type };
|
Int mul = { .i.low = type_size(type_flatten(pointer->type)->pointer), .type = offset->const_expr.ixx.type };
|
||||||
@@ -3091,7 +3092,7 @@ static inline bool sema_expr_analyse_slice(SemaContext *context, Expr *expr)
|
|||||||
end_from_end = expr->subscript_expr.range.end_from_end = false;
|
end_from_end = expr->subscript_expr.range.end_from_end = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (start && end && expr_is_const(start) && expr_is_const(end))
|
if (start && end && sema_cast_const(start) && sema_cast_const(end))
|
||||||
{
|
{
|
||||||
if (!is_lenrange && start_from_end && end_from_end)
|
if (!is_lenrange && start_from_end && end_from_end)
|
||||||
{
|
{
|
||||||
@@ -3793,7 +3794,7 @@ static bool sema_expr_rewrite_to_typeid_property(SemaContext *context, Expr *exp
|
|||||||
{
|
{
|
||||||
TypeProperty property = type_property_by_name(kw);
|
TypeProperty property = type_property_by_name(kw);
|
||||||
|
|
||||||
if (sema_flattened_expr_is_const(context, typeid))
|
if (sema_cast_const(typeid))
|
||||||
{
|
{
|
||||||
Type *type = typeid->const_expr.typeid;
|
Type *type = typeid->const_expr.typeid;
|
||||||
if (!sema_type_property_is_valid_for_type(type, property)) return false;
|
if (!sema_type_property_is_valid_for_type(type, property)) return false;
|
||||||
@@ -3839,6 +3840,101 @@ static bool sema_expr_rewrite_to_typeid_property(SemaContext *context, Expr *exp
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool sema_expr_fold_to_index(Expr *expr, Expr *parent, Range range)
|
||||||
|
{
|
||||||
|
ConstInitializer *init = parent->const_expr.initializer;
|
||||||
|
ConstInitializer *result;
|
||||||
|
assert(!range.start_from_end);
|
||||||
|
ArrayIndex start = exprptr(range.start)->const_expr.ixx.i.low;
|
||||||
|
int len = range_const_len(&range);
|
||||||
|
ArrayIndex end = start + (len == -1 ? 1 : len);
|
||||||
|
switch (init->kind)
|
||||||
|
{
|
||||||
|
case CONST_INIT_ZERO:
|
||||||
|
result = init;
|
||||||
|
goto EVAL;
|
||||||
|
case CONST_INIT_STRUCT:
|
||||||
|
case CONST_INIT_UNION:
|
||||||
|
case CONST_INIT_VALUE:
|
||||||
|
case CONST_INIT_ARRAY_VALUE:
|
||||||
|
UNREACHABLE
|
||||||
|
case CONST_INIT_ARRAY:
|
||||||
|
{
|
||||||
|
ConstInitializer **new = NULL;
|
||||||
|
FOREACH(ConstInitializer *, e, init->init_array.elements)
|
||||||
|
{
|
||||||
|
ArrayIndex index = e->init_array_value.index;
|
||||||
|
if (index < start || index >= end) continue;
|
||||||
|
if (len == -1)
|
||||||
|
{
|
||||||
|
result = e->init_array_value.element;
|
||||||
|
goto EVAL;
|
||||||
|
}
|
||||||
|
vec_add(new, e->init_array_value.element);
|
||||||
|
}
|
||||||
|
result = CALLOCS(ConstInitializer);
|
||||||
|
result->type = expr->type;
|
||||||
|
if (new)
|
||||||
|
{
|
||||||
|
result->kind = CONST_INIT_ARRAY;
|
||||||
|
result->init_array.elements = new;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result->kind = CONST_INIT_ZERO;
|
||||||
|
}
|
||||||
|
goto EVAL;
|
||||||
|
}
|
||||||
|
case CONST_INIT_ARRAY_FULL:
|
||||||
|
{
|
||||||
|
if (len == -1)
|
||||||
|
{
|
||||||
|
result = init->init_array_full[start];
|
||||||
|
goto EVAL;
|
||||||
|
}
|
||||||
|
ConstInitializer **new = NULL;
|
||||||
|
for (ArrayIndex i = start; i < end; i++)
|
||||||
|
{
|
||||||
|
vec_add(new, init->init_array_full[i]);
|
||||||
|
}
|
||||||
|
FOREACH(ConstInitializer *, e, init->init_array.elements)
|
||||||
|
{
|
||||||
|
ArrayIndex index = e->init_array_value.index;
|
||||||
|
if (index < start || index >= end) continue;
|
||||||
|
vec_add(new, e->init_array_value.element);
|
||||||
|
}
|
||||||
|
result = CALLOCS(ConstInitializer);
|
||||||
|
assert(new);
|
||||||
|
result->kind = CONST_INIT_ARRAY;
|
||||||
|
result->init_array.elements = new;
|
||||||
|
result->type = expr->type;
|
||||||
|
goto EVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UNREACHABLE
|
||||||
|
EVAL:
|
||||||
|
switch (result->kind)
|
||||||
|
{
|
||||||
|
case CONST_INIT_ZERO:
|
||||||
|
expr_rewrite_to_const_zero(expr, result->type);
|
||||||
|
break;
|
||||||
|
case CONST_INIT_ARRAY:
|
||||||
|
case CONST_INIT_ARRAY_FULL:
|
||||||
|
expr->const_expr.const_kind = CONST_INITIALIZER;
|
||||||
|
expr->const_expr.initializer = init;
|
||||||
|
expr->type = init->type;
|
||||||
|
break;
|
||||||
|
case CONST_INIT_ARRAY_VALUE:
|
||||||
|
case CONST_INIT_STRUCT:
|
||||||
|
case CONST_INIT_UNION:
|
||||||
|
UNREACHABLE
|
||||||
|
case CONST_INIT_VALUE:
|
||||||
|
expr_replace(expr, result->init_value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
static inline bool sema_expr_fold_to_member(Expr *expr, Expr *parent, Decl *member)
|
static inline bool sema_expr_fold_to_member(Expr *expr, Expr *parent, Decl *member)
|
||||||
{
|
{
|
||||||
ConstInitializer *init = parent->const_expr.initializer;
|
ConstInitializer *init = parent->const_expr.initializer;
|
||||||
@@ -3881,9 +3977,10 @@ EVAL:
|
|||||||
case CONST_INIT_UNION:
|
case CONST_INIT_UNION:
|
||||||
case CONST_INIT_ARRAY:
|
case CONST_INIT_ARRAY:
|
||||||
case CONST_INIT_ARRAY_FULL:
|
case CONST_INIT_ARRAY_FULL:
|
||||||
|
expr->expr_kind = EXPR_CONST;
|
||||||
expr->const_expr.const_kind = CONST_INITIALIZER;
|
expr->const_expr.const_kind = CONST_INITIALIZER;
|
||||||
expr->const_expr.initializer = init;
|
expr->const_expr.initializer = result;
|
||||||
expr->type = init->type;
|
expr->type = result->type;
|
||||||
break;
|
break;
|
||||||
case CONST_INIT_ARRAY_VALUE:
|
case CONST_INIT_ARRAY_VALUE:
|
||||||
UNREACHABLE
|
UNREACHABLE
|
||||||
@@ -4118,8 +4215,51 @@ static inline bool sema_analyse_maybe_dead_expr(SemaContext *context, Expr *expr
|
|||||||
context->active_scope.is_dead = false;
|
context->active_scope.is_dead = false;
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
static bool sema_expr_flatten_assign(Expr *expr)
|
||||||
|
{
|
||||||
|
assert(expr->resolve_status == RESOLVE_DONE);
|
||||||
|
switch (expr->expr_kind)
|
||||||
|
{
|
||||||
|
case EXPR_ACCESS:
|
||||||
|
case EXPR_BITACCESS:
|
||||||
|
{
|
||||||
|
Expr *parent = expr->access_expr.parent;
|
||||||
|
Type *flat = type_flatten(parent->type);
|
||||||
|
switch (flat->type_kind)
|
||||||
|
{
|
||||||
|
case TYPE_UNION:
|
||||||
|
case TYPE_UNTYPED_LIST:
|
||||||
|
case TYPE_BITSTRUCT:
|
||||||
|
case TYPE_STRUCT:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!sema_expr_flatten_assign(expr->access_expr.parent)) return false;
|
||||||
|
if (!sema_expr_fold_to_member(expr, expr->access_expr.parent, expr->access_expr.ref)) return false;
|
||||||
|
return true;
|
||||||
|
|
||||||
static inline void sema_expr_flatten_const(SemaContext *context, Expr *expr)
|
}
|
||||||
|
case EXPR_SUBSCRIPT:
|
||||||
|
{
|
||||||
|
if (!range_is_const(&expr->subscript_expr.range)) return false;
|
||||||
|
Expr *parent = exprptr(expr->subscript_expr.expr);
|
||||||
|
Type *flat_type = type_flatten(parent->type);
|
||||||
|
if (!type_is_any_arraylike(flat_type) || flat_type->type_kind == TYPE_UNTYPED_LIST) return false;
|
||||||
|
if (!sema_expr_flatten_assign(parent)) return false;
|
||||||
|
return sema_expr_fold_to_index(expr, parent, expr->subscript_expr.range);
|
||||||
|
}
|
||||||
|
case EXPR_IDENTIFIER:
|
||||||
|
sema_expr_flatten_const_ident(expr);
|
||||||
|
return expr_is_const(expr);
|
||||||
|
case EXPR_CONST:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void sema_expr_flatten_const_ident(Expr *expr)
|
||||||
{
|
{
|
||||||
if (expr->expr_kind != EXPR_IDENTIFIER) return;
|
if (expr->expr_kind != EXPR_IDENTIFIER) return;
|
||||||
Decl *ident = expr->identifier_expr.decl;
|
Decl *ident = expr->identifier_expr.decl;
|
||||||
@@ -4146,19 +4286,13 @@ static inline void sema_expr_flatten_const(SemaContext *context, Expr *expr)
|
|||||||
}
|
}
|
||||||
Expr *init_expr = ident->var.init_expr;
|
Expr *init_expr = ident->var.init_expr;
|
||||||
if (!init_expr) return;
|
if (!init_expr) return;
|
||||||
sema_expr_flatten_const(context, init_expr);
|
sema_expr_flatten_const_ident(init_expr);
|
||||||
if (expr_is_const(init_expr))
|
if (expr_is_const(init_expr))
|
||||||
{
|
{
|
||||||
expr_replace(expr, expr_copy(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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Analyse "x.y"
|
* Analyse "x.y"
|
||||||
*/
|
*/
|
||||||
@@ -4275,7 +4409,7 @@ CHECK_DEEPER:
|
|||||||
if (flat_type->type_kind == TYPE_SLICE)
|
if (flat_type->type_kind == TYPE_SLICE)
|
||||||
{
|
{
|
||||||
// Handle literal "foo".len which is now a slice.
|
// Handle literal "foo".len which is now a slice.
|
||||||
sema_expr_flatten_const(context, parent);
|
sema_expr_flatten_const_ident(parent);
|
||||||
if (expr_is_const_string(parent))
|
if (expr_is_const_string(parent))
|
||||||
{
|
{
|
||||||
expr_rewrite_const_int(expr, type_isz, parent->const_expr.bytes.len);
|
expr_rewrite_const_int(expr, type_isz, parent->const_expr.bytes.len);
|
||||||
@@ -4340,7 +4474,7 @@ CHECK_DEEPER:
|
|||||||
{
|
{
|
||||||
assert(flat_type->decl->resolve_status == RESOLVE_DONE);
|
assert(flat_type->decl->resolve_status == RESOLVE_DONE);
|
||||||
|
|
||||||
if (sema_flattened_expr_is_const(context, current_parent))
|
if (sema_cast_const(current_parent))
|
||||||
{
|
{
|
||||||
if (current_parent->const_expr.const_kind == CONST_POINTER)
|
if (current_parent->const_expr.const_kind == CONST_POINTER)
|
||||||
{
|
{
|
||||||
@@ -4359,7 +4493,7 @@ CHECK_DEEPER:
|
|||||||
{
|
{
|
||||||
if (flat_type->type_kind == TYPE_ENUM)
|
if (flat_type->type_kind == TYPE_ENUM)
|
||||||
{
|
{
|
||||||
if (sema_flattened_expr_is_const(context, current_parent))
|
if (sema_cast_const(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;
|
||||||
@@ -4372,7 +4506,7 @@ CHECK_DEEPER:
|
|||||||
}
|
}
|
||||||
if (flat_type->type_kind == TYPE_FAULTTYPE || flat_type->type_kind == TYPE_ANYFAULT)
|
if (flat_type->type_kind == TYPE_FAULTTYPE || flat_type->type_kind == TYPE_ANYFAULT)
|
||||||
{
|
{
|
||||||
if (expr_is_const(current_parent))
|
if (sema_cast_const(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;
|
||||||
@@ -4415,7 +4549,7 @@ CHECK_DEEPER:
|
|||||||
Decl *decl = type->decl;
|
Decl *decl = type->decl;
|
||||||
|
|
||||||
Decl *member = sema_decl_stack_find_decl_member(decl, kw);
|
Decl *member = sema_decl_stack_find_decl_member(decl, kw);
|
||||||
if (member && decl_is_enum_kind(decl) && member->decl_kind == DECL_VAR && expr_is_const(parent))
|
if (member && decl_is_enum_kind(decl) && member->decl_kind == DECL_VAR && sema_cast_const(parent))
|
||||||
{
|
{
|
||||||
if (!sema_analyse_decl(context, decl)) return false;
|
if (!sema_analyse_decl(context, decl)) return false;
|
||||||
assert(parent->const_expr.const_kind == CONST_ENUM);
|
assert(parent->const_expr.const_kind == CONST_ENUM);
|
||||||
@@ -4721,6 +4855,14 @@ static inline bool sema_expr_analyse_cast(SemaContext *context, Expr *expr, bool
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool range_is_const(Range *range)
|
||||||
|
{
|
||||||
|
Expr *start = exprptr(range->start);
|
||||||
|
Expr *end = exprptrzero(range->end);
|
||||||
|
if (end && !expr_is_const(end)) return false;
|
||||||
|
if (start && !expr_is_const(start)) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
static inline IndexDiff range_const_len(Range *range)
|
static inline IndexDiff range_const_len(Range *range)
|
||||||
{
|
{
|
||||||
Expr *start = exprptr(range->start);
|
Expr *start = exprptr(range->start);
|
||||||
@@ -5025,10 +5167,9 @@ static bool sema_binary_analyse_ct_common_assign(SemaContext *context, Expr *exp
|
|||||||
|
|
||||||
if (!sema_expr_analyse_binary(context, expr)) return false;
|
if (!sema_expr_analyse_binary(context, expr)) return false;
|
||||||
|
|
||||||
if (!expr_is_const(expr))
|
if (!sema_cast_const(expr))
|
||||||
{
|
{
|
||||||
SEMA_ERROR(exprptr(expr->binary_expr.right), "Expected a constant expression.");
|
RETURN_SEMA_ERROR(exprptr(expr->binary_expr.right), "Expected a constant expression.");
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
left->ct_ident_expr.decl->var.init_expr = expr;
|
left->ct_ident_expr.decl->var.init_expr = expr;
|
||||||
@@ -5081,7 +5222,7 @@ BITSTRUCT_OK:
|
|||||||
RETURN_SEMA_ERROR(right, "The expression may not be optional.");
|
RETURN_SEMA_ERROR(right, "The expression may not be optional.");
|
||||||
}
|
}
|
||||||
// 6. Check for zero in case of div or mod.
|
// 6. Check for zero in case of div or mod.
|
||||||
if (expr_is_const(right))
|
if (sema_cast_const(right))
|
||||||
{
|
{
|
||||||
if (expr->binary_expr.operator == BINARYOP_DIV_ASSIGN)
|
if (expr->binary_expr.operator == BINARYOP_DIV_ASSIGN)
|
||||||
{
|
{
|
||||||
@@ -5678,7 +5819,7 @@ static bool sema_expr_analyse_div(SemaContext *context, Expr *expr, Expr *left,
|
|||||||
if (!sema_binary_analyse_arithmetic_subexpr(context, expr, "Cannot divide %s by %s.", false)) return false;
|
if (!sema_binary_analyse_arithmetic_subexpr(context, expr, "Cannot divide %s by %s.", false)) return false;
|
||||||
|
|
||||||
// 2. Check for a constant 0 on the rhs.
|
// 2. Check for a constant 0 on the rhs.
|
||||||
if (expr_is_const(right))
|
if (sema_cast_const(right))
|
||||||
{
|
{
|
||||||
switch (right->const_expr.const_kind)
|
switch (right->const_expr.const_kind)
|
||||||
{
|
{
|
||||||
@@ -5736,7 +5877,7 @@ static bool sema_expr_analyse_mod(SemaContext *context, Expr *expr, Expr *left,
|
|||||||
if (type_is_float(flat))
|
if (type_is_float(flat))
|
||||||
{
|
{
|
||||||
// 3. a % 0 is not valid, so detect it.
|
// 3. a % 0 is not valid, so detect it.
|
||||||
if (expr_is_const(right) && right->const_expr.fxx.f == 0.0)
|
if (sema_cast_const(right) && right->const_expr.fxx.f == 0.0)
|
||||||
{
|
{
|
||||||
RETURN_SEMA_ERROR(right, "Cannot perform %% with a constant zero.");
|
RETURN_SEMA_ERROR(right, "Cannot perform %% with a constant zero.");
|
||||||
}
|
}
|
||||||
@@ -5753,7 +5894,7 @@ static bool sema_expr_analyse_mod(SemaContext *context, Expr *expr, Expr *left,
|
|||||||
{
|
{
|
||||||
assert(type_is_integer(flat));
|
assert(type_is_integer(flat));
|
||||||
// 3. a % 0 is not valid, so detect it.
|
// 3. a % 0 is not valid, so detect it.
|
||||||
if (expr_is_const(right) && int_is_zero(right->const_expr.ixx)) RETURN_SEMA_ERROR(right, "Cannot perform %% with a constant zero.");
|
if (sema_cast_const(right) && int_is_zero(right->const_expr.ixx)) RETURN_SEMA_ERROR(right, "Cannot perform %% with a constant zero.");
|
||||||
|
|
||||||
// 4. Constant fold
|
// 4. Constant fold
|
||||||
if (expr_both_const(left, right) && sema_constant_fold_ops(left))
|
if (expr_both_const(left, right) && sema_constant_fold_ops(left))
|
||||||
@@ -5858,7 +5999,7 @@ static bool sema_expr_analyse_shift(SemaContext *context, Expr *expr, Expr *left
|
|||||||
if (!cast_implicit(context, left, cast_numeric_arithmetic_promotion(type_no_optional(left->type)))) return false;
|
if (!cast_implicit(context, left, cast_numeric_arithmetic_promotion(type_no_optional(left->type)))) return false;
|
||||||
|
|
||||||
// 4. For a constant rhs side we will make a series of checks.
|
// 4. For a constant rhs side we will make a series of checks.
|
||||||
if (expr_is_const(right))
|
if (sema_cast_const(right))
|
||||||
{
|
{
|
||||||
// 4a. Make sure the value does not exceed the bitsize of
|
// 4a. Make sure the value does not exceed the bitsize of
|
||||||
// the left hand side. We ignore this check for lhs being a constant.
|
// the left hand side. We ignore this check for lhs being a constant.
|
||||||
@@ -5878,7 +6019,7 @@ static bool sema_expr_analyse_shift(SemaContext *context, Expr *expr, Expr *left
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 5. Fold constant expressions.
|
// 5. Fold constant expressions.
|
||||||
if (expr_is_const(left))
|
if (sema_cast_const(left))
|
||||||
{
|
{
|
||||||
bool shr = expr->binary_expr.operator == BINARYOP_SHR;
|
bool shr = expr->binary_expr.operator == BINARYOP_SHR;
|
||||||
expr_replace(expr, left);
|
expr_replace(expr, left);
|
||||||
@@ -5921,7 +6062,7 @@ static bool sema_expr_analyse_shift_assign(SemaContext *context, Expr *expr, Exp
|
|||||||
if (!expr_both_any_integer_or_integer_vector(left, right)) return sema_type_error_on_binop(context, expr);
|
if (!expr_both_any_integer_or_integer_vector(left, right)) return sema_type_error_on_binop(context, expr);
|
||||||
|
|
||||||
// 4. For a constant right hand side we will make a series of checks.
|
// 4. For a constant right hand side we will make a series of checks.
|
||||||
if (expr_is_const(right))
|
if (sema_cast_const(right))
|
||||||
{
|
{
|
||||||
// 4a. Make sure the value does not exceed the bitsize of
|
// 4a. Make sure the value does not exceed the bitsize of
|
||||||
// the left hand side.
|
// the left hand side.
|
||||||
@@ -5980,7 +6121,7 @@ static bool sema_binary_is_unsigned_always_same_comparison(SemaContext *context,
|
|||||||
Type *lhs_type, Type *rhs_type)
|
Type *lhs_type, Type *rhs_type)
|
||||||
{
|
{
|
||||||
if (context->active_scope.flags & (SCOPE_MACRO | SCOPE_ENSURE | SCOPE_ENSURE_MACRO)) return true;
|
if (context->active_scope.flags & (SCOPE_MACRO | SCOPE_ENSURE | SCOPE_ENSURE_MACRO)) return true;
|
||||||
if (!expr_is_const(left) && !expr_is_const(right)) return true;
|
if (!sema_cast_const(left) && !sema_cast_const(right)) return true;
|
||||||
if (!type_is_integer(left->type)) return true;
|
if (!type_is_integer(left->type)) return true;
|
||||||
if (expr_is_const(left) && type_is_unsigned(rhs_type))
|
if (expr_is_const(left) && type_is_unsigned(rhs_type))
|
||||||
{
|
{
|
||||||
@@ -6163,7 +6304,7 @@ static inline bool sema_expr_analyse_deref(SemaContext *context, Expr *expr, boo
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 3. This could be a constant, in which case it is a null which is an error.
|
// 3. This could be a constant, in which case it is a null which is an error.
|
||||||
if (expr_is_const(inner))
|
if (sema_cast_const(inner))
|
||||||
{
|
{
|
||||||
if (failed_ref) goto ON_FAILED;
|
if (failed_ref) goto ON_FAILED;
|
||||||
RETURN_SEMA_ERROR(inner, "Dereferencing null is not allowed, did you do it by mistake?");
|
RETURN_SEMA_ERROR(inner, "Dereferencing null is not allowed, did you do it by mistake?");
|
||||||
@@ -6435,7 +6576,7 @@ static inline bool sema_expr_analyse_bit_not(SemaContext *context, Expr *expr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
VALID_VEC:
|
VALID_VEC:
|
||||||
if (is_bitstruct && expr_is_const(inner))
|
if (is_bitstruct && sema_cast_const(inner))
|
||||||
{
|
{
|
||||||
expr_replace(expr, inner);
|
expr_replace(expr, inner);
|
||||||
sema_invert_bitstruct_const_initializer(expr->const_expr.initializer);
|
sema_invert_bitstruct_const_initializer(expr->const_expr.initializer);
|
||||||
@@ -6509,7 +6650,7 @@ static inline bool sema_expr_analyse_not(SemaContext *context, Expr *expr)
|
|||||||
|
|
||||||
expr->type = type_add_optional(type_bool, IS_OPTIONAL(inner));
|
expr->type = type_add_optional(type_bool, IS_OPTIONAL(inner));
|
||||||
|
|
||||||
if (expr_is_const(inner))
|
if (sema_cast_const(inner))
|
||||||
{
|
{
|
||||||
bool success = cast_explicit(context, inner, expr->type);
|
bool success = cast_explicit(context, inner, expr->type);
|
||||||
assert(success);
|
assert(success);
|
||||||
@@ -7240,7 +7381,7 @@ static inline bool sema_expr_analyse_decl_element(SemaContext *context, Designat
|
|||||||
{
|
{
|
||||||
RETURN_SEMA_ERROR(inner, "Expected an integer index.");
|
RETURN_SEMA_ERROR(inner, "Expected an integer index.");
|
||||||
}
|
}
|
||||||
if (!sema_flattened_expr_is_const(context, inner))
|
if (!sema_cast_const(inner))
|
||||||
{
|
{
|
||||||
RETURN_SEMA_ERROR(inner, "Expected a constant index.");
|
RETURN_SEMA_ERROR(inner, "Expected a constant index.");
|
||||||
}
|
}
|
||||||
@@ -8455,7 +8596,7 @@ static inline bool sema_expr_analyse_ct_concat(SemaContext *context, Expr *conca
|
|||||||
{
|
{
|
||||||
Expr *single_expr = exprs[i];
|
Expr *single_expr = exprs[i];
|
||||||
if (!sema_analyse_expr(context, single_expr)) return false;
|
if (!sema_analyse_expr(context, single_expr)) return false;
|
||||||
if (!expr_is_const(single_expr)) RETURN_SEMA_ERROR(single_expr, "Expected this to evaluate to a constant value.");
|
if (!sema_cast_const(single_expr)) RETURN_SEMA_ERROR(single_expr, "Expected this to evaluate to a constant value.");
|
||||||
if (concat == CONCAT_UNKNOWN)
|
if (concat == CONCAT_UNKNOWN)
|
||||||
{
|
{
|
||||||
element_type = single_expr->type;
|
element_type = single_expr->type;
|
||||||
@@ -8599,7 +8740,7 @@ static inline bool sema_expr_analyse_ct_append(SemaContext *context, Expr *appen
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!sema_analyse_expr(context, list)) return false;
|
if (!sema_analyse_expr(context, list)) return false;
|
||||||
if (!expr_is_const(list)) RETURN_SEMA_ERROR(list, "Expected the list to evaluate to a constant value.");
|
if (!sema_cast_const(list)) RETURN_SEMA_ERROR(list, "Expected the list to evaluate to a constant value.");
|
||||||
Expr **untyped_list = NULL;
|
Expr **untyped_list = NULL;
|
||||||
switch (list->const_expr.const_kind)
|
switch (list->const_expr.const_kind)
|
||||||
{
|
{
|
||||||
@@ -8622,7 +8763,7 @@ static inline bool sema_expr_analyse_ct_append(SemaContext *context, Expr *appen
|
|||||||
{
|
{
|
||||||
Expr *element = exprs[i];
|
Expr *element = exprs[i];
|
||||||
if (!sema_analyse_expr(context, element)) return false;
|
if (!sema_analyse_expr(context, element)) return false;
|
||||||
if (!expr_is_const(element)) RETURN_SEMA_ERROR(element, "Expected the element to evaluate to a constant value.");
|
if (!sema_cast_const(element)) RETURN_SEMA_ERROR(element, "Expected the element to evaluate to a constant value.");
|
||||||
vec_add(untyped_list, element);
|
vec_add(untyped_list, element);
|
||||||
}
|
}
|
||||||
append_expr->expr_kind = EXPR_CONST;
|
append_expr->expr_kind = EXPR_CONST;
|
||||||
@@ -8770,7 +8911,7 @@ static inline bool sema_expr_analyse_retval(SemaContext *context, Expr *expr)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert(return_value);
|
assert(return_value);
|
||||||
if (sema_flattened_expr_is_const(context, return_value))
|
if (expr_is_constant_eval(return_value, CONSTANT_EVAL_GLOBAL_INIT))
|
||||||
{
|
{
|
||||||
expr_replace(expr, copy_expr_single(return_value));
|
expr_replace(expr, copy_expr_single(return_value));
|
||||||
}
|
}
|
||||||
@@ -8993,7 +9134,7 @@ bool sema_analyse_expr_rhs(SemaContext *context, Type *to, Expr *expr, bool allo
|
|||||||
if (to && allow_optional && to_canonical != rhs_type_canonical && rhs_type_canonical->type_kind == TYPE_FAULTTYPE)
|
if (to && allow_optional && to_canonical != rhs_type_canonical && rhs_type_canonical->type_kind == TYPE_FAULTTYPE)
|
||||||
{
|
{
|
||||||
Type *flat = type_flatten(to);
|
Type *flat = type_flatten(to);
|
||||||
if (flat != type_anyfault && flat->type_kind != TYPE_FAULTTYPE && expr_is_const(expr))
|
if (flat != type_anyfault && flat->type_kind != TYPE_FAULTTYPE && sema_cast_const(expr))
|
||||||
{
|
{
|
||||||
if (no_match_ref) goto NO_MATCH_REF;
|
if (no_match_ref) goto NO_MATCH_REF;
|
||||||
print_error_after(expr->span, "You need to add a trailing '?' here to make this an optional.");
|
print_error_after(expr->span, "You need to add a trailing '?' here to make this an optional.");
|
||||||
@@ -9067,7 +9208,7 @@ static ArrayIndex len_from_const_initializer(ConstInitializer *init)
|
|||||||
ArrayIndex sema_len_from_const(Expr *expr)
|
ArrayIndex sema_len_from_const(Expr *expr)
|
||||||
{
|
{
|
||||||
// We also handle the case where we have a cast from a const array.
|
// We also handle the case where we have a cast from a const array.
|
||||||
if (!expr_is_const(expr))
|
if (!sema_cast_const(expr))
|
||||||
{
|
{
|
||||||
if (type_flatten(expr->type)->type_kind != TYPE_SLICE) return -1;
|
if (type_flatten(expr->type)->type_kind != TYPE_SLICE) return -1;
|
||||||
if (expr->expr_kind == EXPR_SLICE)
|
if (expr->expr_kind == EXPR_SLICE)
|
||||||
@@ -9079,7 +9220,7 @@ ArrayIndex sema_len_from_const(Expr *expr)
|
|||||||
Expr *inner = exprptr(expr->cast_expr.expr);
|
Expr *inner = exprptr(expr->cast_expr.expr);
|
||||||
if (inner->expr_kind != EXPR_UNARY || inner->unary_expr.operator != UNARYOP_ADDR) return -1;
|
if (inner->expr_kind != EXPR_UNARY || inner->unary_expr.operator != UNARYOP_ADDR) return -1;
|
||||||
inner = inner->unary_expr.expr;
|
inner = inner->unary_expr.expr;
|
||||||
if (!expr_is_const(inner)) return -1;
|
if (!sema_cast_const(inner)) return -1;
|
||||||
expr = inner;
|
expr = inner;
|
||||||
}
|
}
|
||||||
switch (expr->const_expr.const_kind)
|
switch (expr->const_expr.const_kind)
|
||||||
@@ -9109,10 +9250,10 @@ static inline bool sema_cast_ct_ident_rvalue(SemaContext *context, Expr *expr)
|
|||||||
Expr *copy = copy_expr_single(decl->var.init_expr);
|
Expr *copy = copy_expr_single(decl->var.init_expr);
|
||||||
if (!copy)
|
if (!copy)
|
||||||
{
|
{
|
||||||
SEMA_ERROR(expr, "'%s' was not yet initialized to any value, assign a value to it before use.", decl->name);
|
RETURN_SEMA_ERROR(expr, "'%s' was not yet initialized to any value, assign a value to it before use.", decl->name);
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
if (!sema_analyse_expr(context, copy)) return false;
|
if (!sema_analyse_expr(context, copy)) return false;
|
||||||
|
sema_cast_const(copy);
|
||||||
expr_replace(expr, copy);
|
expr_replace(expr, copy);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -9144,11 +9285,8 @@ static inline bool sema_cast_rvalue(SemaContext *context, Expr *expr)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// We may have kept FOO.x.y as a reference, fold it now if y is not an aggregate.
|
// 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))
|
sema_expr_flatten_const_ident(expr->access_expr.parent);
|
||||||
{
|
return true;
|
||||||
return sema_expr_fold_to_member(expr, expr->access_expr.parent, expr->access_expr.ref);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case EXPR_TYPEINFO:
|
case EXPR_TYPEINFO:
|
||||||
RETURN_SEMA_ERROR(expr, "A type must be followed by either (...) or '.'.");
|
RETURN_SEMA_ERROR(expr, "A type must be followed by either (...) or '.'.");
|
||||||
case EXPR_CT_IDENT:
|
case EXPR_CT_IDENT:
|
||||||
@@ -9195,10 +9333,9 @@ 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 (!sema_flattened_expr_is_const(context, expr))
|
if (!sema_cast_const(expr))
|
||||||
{
|
{
|
||||||
SEMA_ERROR(expr, "Expected a compile time expression.");
|
RETURN_SEMA_ERROR(expr, "Expected a compile time expression.");
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -9294,6 +9431,11 @@ bool sema_analyse_expr(SemaContext *context, Expr *expr)
|
|||||||
return sema_analyse_expr_lvalue(context, expr) && sema_cast_rvalue(context, expr);
|
return sema_analyse_expr_lvalue(context, expr) && sema_cast_rvalue(context, expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool sema_cast_const(Expr *expr)
|
||||||
|
{
|
||||||
|
return sema_expr_flatten_assign(expr);
|
||||||
|
}
|
||||||
|
|
||||||
static inline int64_t expr_get_index_max(Expr *expr)
|
static inline int64_t expr_get_index_max(Expr *expr)
|
||||||
{
|
{
|
||||||
if (expr_is_const_untyped_list(expr))
|
if (expr_is_const_untyped_list(expr))
|
||||||
@@ -9496,7 +9638,7 @@ bool sema_insert_method_call(SemaContext *context, Expr *method_call, Decl *meth
|
|||||||
bool sema_bit_assignment_check(SemaContext *context, Expr *right, Decl *member)
|
bool sema_bit_assignment_check(SemaContext *context, Expr *right, Decl *member)
|
||||||
{
|
{
|
||||||
// Don't check non-consts and non integers.
|
// Don't check non-consts and non integers.
|
||||||
if (!expr_is_const(right) || !type_is_integer(right->type)) return true;
|
if (!sema_cast_const(right) || !type_is_integer(right->type)) return true;
|
||||||
|
|
||||||
unsigned bits = member->var.end_bit - member->var.start_bit + 1;
|
unsigned bits = member->var.end_bit - member->var.start_bit + 1;
|
||||||
|
|
||||||
|
|||||||
@@ -383,7 +383,7 @@ static inline bool sema_expr_analyse_untyped_initializer(SemaContext *context, E
|
|||||||
FOREACH(Expr *, element, init_list)
|
FOREACH(Expr *, element, init_list)
|
||||||
{
|
{
|
||||||
if (!sema_analyse_expr(context, element)) return false;
|
if (!sema_analyse_expr(context, element)) return false;
|
||||||
if (!expr_is_const(element))
|
if (!sema_cast_const(element))
|
||||||
{
|
{
|
||||||
RETURN_SEMA_ERROR(element, "An untyped list can only have "
|
RETURN_SEMA_ERROR(element, "An untyped list can only have "
|
||||||
"constant elements, you can try "
|
"constant elements, you can try "
|
||||||
|
|||||||
@@ -95,7 +95,6 @@ void cast_promote_vararg(SemaContext *context, 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);
|
|
||||||
Decl *sema_analyse_parameterized_identifier(SemaContext *c, Path *decl_path, const char *name, SourceSpan span, Expr **params);
|
Decl *sema_analyse_parameterized_identifier(SemaContext *c, Path *decl_path, const char *name, SourceSpan span, Expr **params);
|
||||||
Type *sema_resolve_type_get_func(Signature *signature, CallABI abi);
|
Type *sema_resolve_type_get_func(Signature *signature, CallABI abi);
|
||||||
INLINE bool sema_set_abi_alignment(SemaContext *context, Type *type, AlignSize *result);
|
INLINE bool sema_set_abi_alignment(SemaContext *context, Type *type, AlignSize *result);
|
||||||
|
|||||||
@@ -368,7 +368,7 @@ void sema_analysis_pass_register_conditional_units(Module *module)
|
|||||||
}
|
}
|
||||||
Expr *expr = if_attr->exprs[0];
|
Expr *expr = if_attr->exprs[0];
|
||||||
if (!sema_analyse_ct_expr(&context, expr)) goto FAIL_CONTEXT;
|
if (!sema_analyse_ct_expr(&context, expr)) goto FAIL_CONTEXT;
|
||||||
if (!expr_is_const(expr) || expr->type->canonical != type_bool)
|
if (!sema_cast_const(expr) || expr->type->canonical != type_bool)
|
||||||
{
|
{
|
||||||
PRINT_ERROR_AT(expr, "Expected a constant boolean expression.");
|
PRINT_ERROR_AT(expr, "Expected a constant boolean expression.");
|
||||||
goto FAIL_CONTEXT;
|
goto FAIL_CONTEXT;
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ static inline bool sema_analyse_assert_stmt(SemaContext *context, Ast *statement
|
|||||||
// If it's ensure (and an error) we print an error.
|
// If it's ensure (and an error) we print an error.
|
||||||
if (!context->active_scope.jump_end && !context->active_scope.is_dead)
|
if (!context->active_scope.jump_end && !context->active_scope.is_dead)
|
||||||
{
|
{
|
||||||
if (message_expr && expr_is_const(message_expr) && vec_size(statement->assert_stmt.args))
|
if (message_expr && sema_cast_const(message_expr) && vec_size(statement->assert_stmt.args))
|
||||||
{
|
{
|
||||||
RETURN_SEMA_ERROR(expr, "%.*s", EXPAND_EXPR_STRING(message_expr));
|
RETURN_SEMA_ERROR(expr, "%.*s", EXPAND_EXPR_STRING(message_expr));
|
||||||
}
|
}
|
||||||
@@ -350,7 +350,7 @@ static inline bool sema_return_optional_check_is_valid_in_scope(SemaContext *con
|
|||||||
if (!IS_OPTIONAL(ret_expr) || !context->call_env.opt_returns) return true;
|
if (!IS_OPTIONAL(ret_expr) || !context->call_env.opt_returns) return true;
|
||||||
if (ret_expr->expr_kind != EXPR_OPTIONAL) return true;
|
if (ret_expr->expr_kind != EXPR_OPTIONAL) return true;
|
||||||
Expr *inner = ret_expr->inner_expr;
|
Expr *inner = ret_expr->inner_expr;
|
||||||
if (!expr_is_const(inner)) return true;
|
if (!sema_cast_const(inner)) return true;
|
||||||
assert(ret_expr->inner_expr->const_expr.const_kind == CONST_ERR);
|
assert(ret_expr->inner_expr->const_expr.const_kind == CONST_ERR);
|
||||||
Decl *fault = ret_expr->inner_expr->const_expr.enum_err_val;
|
Decl *fault = ret_expr->inner_expr->const_expr.enum_err_val;
|
||||||
FOREACH(Decl *, opt, context->call_env.opt_returns)
|
FOREACH(Decl *, opt, context->call_env.opt_returns)
|
||||||
@@ -374,7 +374,7 @@ static bool sema_analyse_macro_constant_ensures(SemaContext *context, Expr *ret_
|
|||||||
|
|
||||||
// If the return expression can't be flattened to a constant value, then
|
// If the return expression can't be flattened to a constant value, then
|
||||||
// we won't be able to do any constant ensure checks anyway, so skip.
|
// we won't be able to do any constant ensure checks anyway, so skip.
|
||||||
if (!sema_flattened_expr_is_const(context, ret_expr)) return true;
|
if (!sema_cast_const(ret_expr)) return true;
|
||||||
|
|
||||||
AstId doc_directive = context->current_macro->func_decl.docs;
|
AstId doc_directive = context->current_macro->func_decl.docs;
|
||||||
// We store the old return_expr for retval
|
// We store the old return_expr for retval
|
||||||
@@ -2108,7 +2108,7 @@ static bool sema_analyse_nextcase_stmt(SemaContext *context, Ast *statement)
|
|||||||
{
|
{
|
||||||
if (case_stmt->ast_kind == AST_DEFAULT_STMT) continue;
|
if (case_stmt->ast_kind == AST_DEFAULT_STMT) continue;
|
||||||
Expr *expr = exprptr(case_stmt->case_stmt.expr);
|
Expr *expr = exprptr(case_stmt->case_stmt.expr);
|
||||||
if (expr_is_const(expr) && expr->const_expr.typeid == type)
|
if (sema_cast_const(expr) && expr->const_expr.typeid == type)
|
||||||
{
|
{
|
||||||
statement->nextcase_stmt.case_switch_stmt = astid(case_stmt);
|
statement->nextcase_stmt.case_switch_stmt = astid(case_stmt);
|
||||||
return true;
|
return true;
|
||||||
@@ -2124,13 +2124,13 @@ static bool sema_analyse_nextcase_stmt(SemaContext *context, Ast *statement)
|
|||||||
|
|
||||||
statement->nextcase_stmt.defer_id = context_get_defers(context, context->active_scope.defer_last, parent->switch_stmt.defer, true);
|
statement->nextcase_stmt.defer_id = context_get_defers(context, context->active_scope.defer_last, parent->switch_stmt.defer, true);
|
||||||
|
|
||||||
if (expr_is_const(value))
|
if (sema_cast_const(value))
|
||||||
{
|
{
|
||||||
FOREACH(Ast *, case_stmt, parent->switch_stmt.cases)
|
FOREACH(Ast *, case_stmt, parent->switch_stmt.cases)
|
||||||
{
|
{
|
||||||
Expr *from = exprptr(case_stmt->case_stmt.expr);
|
Expr *from = exprptr(case_stmt->case_stmt.expr);
|
||||||
if (case_stmt->ast_kind == AST_DEFAULT_STMT) continue;
|
if (case_stmt->ast_kind == AST_DEFAULT_STMT) continue;
|
||||||
if (!expr_is_const(from)) goto VARIABLE_JUMP;
|
if (!sema_cast_const(from)) goto VARIABLE_JUMP;
|
||||||
ExprConst *const_expr = &from->const_expr;
|
ExprConst *const_expr = &from->const_expr;
|
||||||
ExprConst *to_const_expr = case_stmt->case_stmt.to_expr ? &exprptr(case_stmt->case_stmt.to_expr)->const_expr : const_expr;
|
ExprConst *to_const_expr = case_stmt->case_stmt.to_expr ? &exprptr(case_stmt->case_stmt.to_expr)->const_expr : const_expr;
|
||||||
if (expr_const_in_range(&value->const_expr, const_expr, to_const_expr))
|
if (expr_const_in_range(&value->const_expr, const_expr, to_const_expr))
|
||||||
@@ -2242,7 +2242,7 @@ static inline bool sema_check_type_case(SemaContext *context, Type *switch_type,
|
|||||||
Expr *expr = exprptr(case_stmt->case_stmt.expr);
|
Expr *expr = exprptr(case_stmt->case_stmt.expr);
|
||||||
if (!sema_analyse_expr_rhs(context, type_typeid, expr, false, NULL)) return false;
|
if (!sema_analyse_expr_rhs(context, type_typeid, expr, false, NULL)) return false;
|
||||||
|
|
||||||
if (expr_is_const(expr))
|
if (sema_cast_const(expr))
|
||||||
{
|
{
|
||||||
Type *my_type = expr->const_expr.typeid;
|
Type *my_type = expr->const_expr.typeid;
|
||||||
for (unsigned i = 0; i < index; i++)
|
for (unsigned i = 0; i < index; i++)
|
||||||
@@ -2250,7 +2250,7 @@ static inline bool sema_check_type_case(SemaContext *context, Type *switch_type,
|
|||||||
Ast *other = cases[i];
|
Ast *other = cases[i];
|
||||||
if (other->ast_kind != AST_CASE_STMT) continue;
|
if (other->ast_kind != AST_CASE_STMT) continue;
|
||||||
Expr *other_expr = exprptr(other->case_stmt.expr);
|
Expr *other_expr = exprptr(other->case_stmt.expr);
|
||||||
if (expr_is_const(other_expr) && other_expr->const_expr.typeid == my_type)
|
if (sema_cast_const(other_expr) && other_expr->const_expr.typeid == my_type)
|
||||||
{
|
{
|
||||||
SEMA_ERROR(case_stmt, "The same type appears more than once.");
|
SEMA_ERROR(case_stmt, "The same type appears more than once.");
|
||||||
SEMA_NOTE(other, "Here is the case with that type.");
|
SEMA_NOTE(other, "Here is the case with that type.");
|
||||||
@@ -2272,13 +2272,13 @@ static inline bool sema_check_value_case(SemaContext *context, Type *switch_type
|
|||||||
if (to_expr && !sema_analyse_expr_rhs(context, switch_type, to_expr, false, NULL)) return false;
|
if (to_expr && !sema_analyse_expr_rhs(context, switch_type, to_expr, false, NULL)) return false;
|
||||||
|
|
||||||
bool is_range = to_expr != NULL;
|
bool is_range = to_expr != NULL;
|
||||||
bool first_is_const = expr_is_const(expr);
|
bool first_is_const = sema_cast_const(expr);
|
||||||
if (!is_range && !first_is_const)
|
if (!is_range && !first_is_const)
|
||||||
{
|
{
|
||||||
*if_chained = true;
|
*if_chained = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (is_range && (!expr_is_const_int(expr) || !expr_is_const(to_expr)))
|
if (is_range && (!expr_is_const_int(expr) || !sema_cast_const(to_expr)))
|
||||||
{
|
{
|
||||||
sema_error_at(context, extend_span_with_token(expr->span, to_expr->span), "Ranges must be constant integers.");
|
sema_error_at(context, extend_span_with_token(expr->span, to_expr->span), "Ranges must be constant integers.");
|
||||||
return false;
|
return false;
|
||||||
@@ -2309,7 +2309,7 @@ static inline bool sema_check_value_case(SemaContext *context, Type *switch_type
|
|||||||
Ast *other = cases[i];
|
Ast *other = cases[i];
|
||||||
if (other->ast_kind != AST_CASE_STMT) continue;
|
if (other->ast_kind != AST_CASE_STMT) continue;
|
||||||
Expr *other_expr = exprptr(other->case_stmt.expr);
|
Expr *other_expr = exprptr(other->case_stmt.expr);
|
||||||
if (!expr_is_const(other_expr)) continue;
|
if (!sema_cast_const(other_expr)) continue;
|
||||||
ExprConst *other_const = &other_expr->const_expr;
|
ExprConst *other_const = &other_expr->const_expr;
|
||||||
ExprConst *other_to_const = other->case_stmt.to_expr ? &exprptr(other->case_stmt.to_expr)->const_expr : other_const;
|
ExprConst *other_to_const = other->case_stmt.to_expr ? &exprptr(other->case_stmt.to_expr)->const_expr : other_const;
|
||||||
if (expr_const_in_range(const_expr, other_const, other_to_const))
|
if (expr_const_in_range(const_expr, other_const, other_to_const))
|
||||||
@@ -2439,7 +2439,7 @@ static bool sema_analyse_switch_body(SemaContext *context, Ast *statement, Sourc
|
|||||||
Ast *next = (i < case_count - 1) ? cases[i + 1] : NULL;
|
Ast *next = (i < case_count - 1) ? cases[i + 1] : NULL;
|
||||||
PUSH_NEXT(next, statement);
|
PUSH_NEXT(next, statement);
|
||||||
Ast *body = stmt->case_stmt.body;
|
Ast *body = stmt->case_stmt.body;
|
||||||
if (stmt->ast_kind == AST_CASE_STMT && body && type_switch && var_holder && expr_is_const(exprptr(stmt->case_stmt.expr)))
|
if (stmt->ast_kind == AST_CASE_STMT && body && type_switch && var_holder && sema_cast_const(exprptr(stmt->case_stmt.expr)))
|
||||||
{
|
{
|
||||||
if (any_switch->is_assign)
|
if (any_switch->is_assign)
|
||||||
{
|
{
|
||||||
@@ -2570,7 +2570,7 @@ static inline bool sema_analyse_ct_switch_stmt(SemaContext *context, Ast *statem
|
|||||||
if (!sema_analyse_expr_rhs(context, type, expr, false, NULL)) goto FAILED;
|
if (!sema_analyse_expr_rhs(context, type, expr, false, NULL)) goto FAILED;
|
||||||
if (to_expr && !sema_analyse_expr_rhs(context, type, to_expr, false, NULL)) goto FAILED;
|
if (to_expr && !sema_analyse_expr_rhs(context, type, to_expr, false, NULL)) goto FAILED;
|
||||||
}
|
}
|
||||||
if (!expr_is_const(expr))
|
if (!sema_cast_const(expr))
|
||||||
{
|
{
|
||||||
SEMA_ERROR(expr, "The $case must have a constant expression.");
|
SEMA_ERROR(expr, "The $case must have a constant expression.");
|
||||||
goto FAILED;
|
goto FAILED;
|
||||||
@@ -2581,7 +2581,7 @@ static inline bool sema_analyse_ct_switch_stmt(SemaContext *context, Ast *statem
|
|||||||
if (matched_case == case_count) matched_case = (int)i;
|
if (matched_case == case_count) matched_case = (int)i;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (to_expr && !expr_is_const(to_expr))
|
if (to_expr && !sema_cast_const(to_expr))
|
||||||
{
|
{
|
||||||
SEMA_ERROR(to_expr, "The $case must have a constant expression.");
|
SEMA_ERROR(to_expr, "The $case must have a constant expression.");
|
||||||
goto FAILED;
|
goto FAILED;
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ bool sema_resolve_array_like_len(SemaContext *context, TypeInfo *type_info, Arra
|
|||||||
if (!sema_analyse_expr(context, len_expr)) return type_info_poison(type_info);
|
if (!sema_analyse_expr(context, len_expr)) return type_info_poison(type_info);
|
||||||
|
|
||||||
// A constant expression is assumed.
|
// A constant expression is assumed.
|
||||||
if (!expr_is_const(len_expr))
|
if (!sema_cast_const(len_expr))
|
||||||
{
|
{
|
||||||
SEMA_ERROR(len_expr, "Expected a constant value as length.");
|
SEMA_ERROR(len_expr, "Expected a constant value as length.");
|
||||||
return type_info_poison(type_info);
|
return type_info_poison(type_info);
|
||||||
@@ -186,7 +186,7 @@ static inline bool sema_resolve_array_type(SemaContext *context, TypeInfo *type,
|
|||||||
default:
|
default:
|
||||||
UNREACHABLE
|
UNREACHABLE
|
||||||
}
|
}
|
||||||
assert(!type->array.len || expr_is_const(type->array.len));
|
assert(!type->array.len || sema_cast_const(type->array.len));
|
||||||
type->resolve_status = RESOLVE_DONE;
|
type->resolve_status = RESOLVE_DONE;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -328,7 +328,7 @@ INLINE bool sema_resolve_typefrom(SemaContext *context, TypeInfo *type_info)
|
|||||||
{
|
{
|
||||||
Expr *expr = type_info->unresolved_type_expr;
|
Expr *expr = type_info->unresolved_type_expr;
|
||||||
if (!sema_analyse_expr(context, expr)) return false;
|
if (!sema_analyse_expr(context, expr)) return false;
|
||||||
if (!expr_is_const(expr) || expr->const_expr.const_kind != CONST_TYPEID)
|
if (!sema_cast_const(expr) || expr->const_expr.const_kind != CONST_TYPEID)
|
||||||
{
|
{
|
||||||
RETURN_SEMA_ERROR(expr, "Expected a constant typeid value.");
|
RETURN_SEMA_ERROR(expr, "Expected a constant typeid value.");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,6 +92,22 @@ fn void! remove_if()
|
|||||||
assert(test.array_view() == int[]{11, 10, 20});
|
assert(test.array_view() == int[]{11, 10, 20});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn void! init_with_array()
|
||||||
|
{
|
||||||
|
IntList foo;
|
||||||
|
foo.new_init_with_array({ 1, 2, 3});
|
||||||
|
assert(foo.len() == 3);
|
||||||
|
assert(foo[2] == 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn void! init_with_temp_array()
|
||||||
|
{
|
||||||
|
IntList foo;
|
||||||
|
foo.temp_init_with_array({ 1, 2, 3});
|
||||||
|
assert(foo.len() == 3);
|
||||||
|
assert(foo[2] == 3);
|
||||||
|
}
|
||||||
|
|
||||||
fn void! remove_using_test()
|
fn void! remove_using_test()
|
||||||
{
|
{
|
||||||
IntList test;
|
IntList test;
|
||||||
|
|||||||
Reference in New Issue
Block a user