mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Fix case of very long literal int type values. Fix to bigint compile time truncation. Check decl enum implicit overflow.
This commit is contained in:
@@ -767,16 +767,18 @@ Int int_conv(Int op, TypeKind to_type)
|
||||
}
|
||||
// Extending from a signed to unsigned
|
||||
int shift = 128 - to_bitsize;
|
||||
// Cut off the top.
|
||||
// Cut off the top of the signed bits
|
||||
// 11101 -> 11010 -> 01101
|
||||
return (Int){ i128_lshr64(i128_shl64(op.i, shift), shift), to_type };
|
||||
}
|
||||
// The other case is cutting down bits.
|
||||
int shift = 128 - to_bitsize;
|
||||
// Cut off the top.
|
||||
if (from_signed)
|
||||
Int128 without_top_bits = i128_lshr64(i128_shl64(op.i, shift), shift);
|
||||
if (to_signed)
|
||||
{
|
||||
return (Int){ i128_ashr64(i128_shl64(op.i, shift), shift), to_type };
|
||||
return (Int){ i128_ashr64(i128_shl64(without_top_bits, shift), shift), to_type };
|
||||
}
|
||||
return (Int){ i128_lshr64(i128_shl64(op.i, shift), shift), to_type };
|
||||
return (Int) { without_top_bits, to_type };
|
||||
}
|
||||
|
||||
Int int_div(Int op1, Int op2)
|
||||
|
||||
@@ -1781,7 +1781,6 @@ static inline void llvm_emit_const_initialize_reference(GenContext *c, BEValue *
|
||||
}
|
||||
if (initializer->kind == CONST_INIT_ZERO)
|
||||
{
|
||||
REMINDER("Optimize this for few elements");
|
||||
// In case of a zero, optimize.
|
||||
llvm_emit_memclear(c, ref);
|
||||
return;
|
||||
@@ -4738,27 +4737,31 @@ BEValue llvm_emit_assign_expr(GenContext *c, BEValue *ref, Expr *expr, LLVMValue
|
||||
|
||||
|
||||
|
||||
static inline void gencontext_emit_failable(GenContext *context, BEValue *be_value, Expr *expr)
|
||||
static inline void llvm_emit_failable(GenContext *c, BEValue *be_value, Expr *expr)
|
||||
{
|
||||
Expr *fail = expr->inner_expr;
|
||||
if (context->error_var)
|
||||
// If there is an error value, assign to it.
|
||||
if (c->error_var)
|
||||
{
|
||||
assert(context->error_var);
|
||||
llvm_emit_expr(context, be_value, fail);
|
||||
REMINDER("fix failable");
|
||||
LLVMBuildStore(context->builder, llvm_value_rvalue_store(context, be_value),
|
||||
llvm_emit_bitcast(context, context->error_var, type_get_ptr(fail->type)));
|
||||
assert(c->error_var);
|
||||
llvm_emit_expr(c, be_value, fail);
|
||||
llvm_store_bevalue_dest_aligned(c, c->error_var, be_value);
|
||||
}
|
||||
llvm_emit_br(context, context->catch_block);
|
||||
LLVMBasicBlockRef ignored_block = llvm_basic_block_new(context, "postfailed");
|
||||
llvm_emit_block(context, ignored_block);
|
||||
// Branch to the catch
|
||||
llvm_emit_br(c, c->catch_block);
|
||||
// Create an empty block
|
||||
LLVMBasicBlockRef ignored_block = llvm_basic_block_new(c, "postfailed");
|
||||
llvm_emit_block(c, ignored_block);
|
||||
|
||||
// Finally we need to replace the result with something undefined here.
|
||||
// It will be optimized away.
|
||||
Type *type = type_no_fail(expr->type);
|
||||
if (type->canonical == type_void)
|
||||
{
|
||||
llvm_value_set(be_value, NULL, type_void);
|
||||
return;
|
||||
}
|
||||
llvm_value_set(be_value, LLVMGetUndef(llvm_get_type(context, type)), type);
|
||||
llvm_value_set(be_value, LLVMGetUndef(llvm_get_type(c, type)), type);
|
||||
}
|
||||
|
||||
static inline LLVMValueRef llvm_update_vector(GenContext *c, LLVMValueRef vector, LLVMValueRef value, ArrayIndex index, bool *is_const)
|
||||
@@ -5027,7 +5030,7 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr)
|
||||
llvm_emit_len(c, value, expr);
|
||||
return;
|
||||
case EXPR_FAILABLE:
|
||||
gencontext_emit_failable(c, value, expr);
|
||||
llvm_emit_failable(c, value, expr);
|
||||
return;
|
||||
case EXPR_TRY:
|
||||
llvm_emit_try_expr(c, value, expr);
|
||||
|
||||
@@ -952,11 +952,12 @@ static Expr *parse_placeholder(Context *context, Expr *left)
|
||||
|
||||
static int read_num_type(const char *string, const char *end)
|
||||
{
|
||||
REMINDER("Limit num type reader");
|
||||
int i = 0;
|
||||
if (string[0] == '0') return -1;
|
||||
while (string < end)
|
||||
{
|
||||
i *= 10;
|
||||
if (i > 1024) return i;
|
||||
i += *(string++) - '0';
|
||||
}
|
||||
return i;
|
||||
@@ -1079,7 +1080,7 @@ static Expr *parse_integer(Context *context, Expr *left)
|
||||
{
|
||||
if (!is_power_of_two(type_bits) || type_bits > 128)
|
||||
{
|
||||
SEMA_TOKEN_ERROR(context->tok, "Integer width should be 8, 16, 32, 64 or 128.");
|
||||
SEMA_TOKEN_ERROR(context->tok, "Integer type suffix should be i8, i16, i32, i64 or i128.");
|
||||
return poisoned_expr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -741,9 +741,10 @@ static inline bool sema_analyse_enum(Context *context, Decl *decl)
|
||||
unsigned enums = vec_size(decl->enums.values);
|
||||
Int128 value = { 0, 0 };
|
||||
|
||||
Decl **enum_values = decl->enums.values;
|
||||
for (unsigned i = 0; i < enums; i++)
|
||||
{
|
||||
Decl *enum_value = decl->enums.values[i];
|
||||
Decl *enum_value = enum_values[i];
|
||||
enum_value->type = decl->type;
|
||||
DEBUG_LOG("* Checking enum constant %s.", enum_value->name);
|
||||
enum_value->enum_constant.ordinal = i;
|
||||
@@ -762,8 +763,15 @@ static inline bool sema_analyse_enum(Context *context, Decl *decl)
|
||||
expr = expr_new(EXPR_CONST, source_span_from_token_id(enum_value->name_token));
|
||||
expr->type = type;
|
||||
expr->resolve_status = RESOLVE_NOT_DONE;
|
||||
REMINDER("Do range check");
|
||||
expr->const_expr.ixx = (Int) { value, canonical->type_kind };
|
||||
if (expr_const_will_overflow(&expr->const_expr, canonical->type_kind))
|
||||
{
|
||||
SEMA_ERROR(enum_value,
|
||||
"The enum value would implicitly be %s which does not fit in %s.",
|
||||
i128_to_string(value, 10, type_is_signed(canonical)),
|
||||
type_quoted_error_string(type));
|
||||
return false;
|
||||
}
|
||||
expr->const_expr.const_kind = CONST_INTEGER;
|
||||
expr->const_expr.narrowable = true;
|
||||
expr->type = canonical;
|
||||
@@ -794,7 +802,7 @@ static inline bool sema_analyse_enum(Context *context, Decl *decl)
|
||||
}
|
||||
|
||||
// Update the value
|
||||
value = i128_add64(value, 1);
|
||||
value = i128_add64(expr->const_expr.ixx.i, 1);
|
||||
DEBUG_LOG("* Value: %s", expr_const_to_error_string(&expr->const_expr));
|
||||
enum_value->resolve_status = RESOLVE_DONE;
|
||||
}
|
||||
|
||||
4
test/test_suite/literals/bad_bitwidth.c3
Normal file
4
test/test_suite/literals/bad_bitwidth.c3
Normal file
@@ -0,0 +1,4 @@
|
||||
int i = 4i15; // #error: Integer type suffix should be i8, i16, i32, i64 or i128
|
||||
int j = 4i1024; // #error: Integer type suffix should be i8, i16, i32, i64 or i128
|
||||
int k = 4i65536; // #error: Integer type suffix should be i8, i16, i32, i64 or i128
|
||||
int l = 4i016; // #error: Integer type suffix should be i8, i16, i32, i64 or i128
|
||||
5
test/test_suite/types/enum_implicit_overflow.c3
Normal file
5
test/test_suite/types/enum_implicit_overflow.c3
Normal file
@@ -0,0 +1,5 @@
|
||||
enum Foo : char
|
||||
{
|
||||
MY_VAL1 = 255,
|
||||
MY_VAL2, // #error: The enum value would implicitly be 256 which does not fit in 'char'
|
||||
}
|
||||
Reference in New Issue
Block a user