mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Change cast and int rules: constant folding always starts. Promotion using left side on all operands to bit width. Implicit narrowing to max size on right hand side.
This commit is contained in:
committed by
Christoffer Lerno
parent
8a7f37e4d3
commit
07595df412
@@ -25,7 +25,7 @@ Checks: >
|
|||||||
WarningsAsErrors: "*"
|
WarningsAsErrors: "*"
|
||||||
|
|
||||||
CheckOptions:
|
CheckOptions:
|
||||||
- { key: readability-function-cognitive-complexity.Threshold, value: 40 }
|
- { key: readability-function-cognitive-complexity.Threshold, value: 100 }
|
||||||
- { key: readability-identifier-naming.StructCase, value: CamelCase }
|
- { key: readability-identifier-naming.StructCase, value: CamelCase }
|
||||||
- { key: readability-identifier-naming.FunctionCase, value: lower_case }
|
- { key: readability-identifier-naming.FunctionCase, value: lower_case }
|
||||||
- { key: readability-identifier-naming.VariableCase, value: lower_case }
|
- { key: readability-identifier-naming.VariableCase, value: lower_case }
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ public func uint fnv32(char[] data)
|
|||||||
uint h = 0x811c9dc5;
|
uint h = 0x811c9dc5;
|
||||||
foreach (char x : data)
|
foreach (char x : data)
|
||||||
{
|
{
|
||||||
h = (h *% 0x01000193) ^ x;
|
h = (h * 0x01000193) ^ x;
|
||||||
}
|
}
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
@@ -67,7 +67,7 @@ public func ulong fnv64(char[] data)
|
|||||||
ulong h = 0xcbf29ce484222325;
|
ulong h = 0xcbf29ce484222325;
|
||||||
foreach (char x : data)
|
foreach (char x : data)
|
||||||
{
|
{
|
||||||
h = (h *% 0x100000001b3) ^ x;
|
h = (h * 0x100000001b3) ^ x;
|
||||||
}
|
}
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
@@ -77,7 +77,7 @@ public func uint fnv32a(char[] data)
|
|||||||
uint h = 0x811c9dc5;
|
uint h = 0x811c9dc5;
|
||||||
foreach (char x : data)
|
foreach (char x : data)
|
||||||
{
|
{
|
||||||
h = (h ^ x) *% 0x01000193;
|
h = (h ^ x) * 0x01000193;
|
||||||
}
|
}
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
@@ -87,7 +87,7 @@ public func ulong fnv64a(char[] data)
|
|||||||
ulong h = 0xcbf29ce484222325;
|
ulong h = 0xcbf29ce484222325;
|
||||||
foreach (char x : data)
|
foreach (char x : data)
|
||||||
{
|
{
|
||||||
h = (h ^ x) *% 0x100000001b3;
|
h = (h ^ x) * 0x100000001b3;
|
||||||
}
|
}
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -169,6 +169,7 @@ typedef struct
|
|||||||
bool emit_llvm;
|
bool emit_llvm;
|
||||||
bool emit_bitcode;
|
bool emit_bitcode;
|
||||||
bool test_mode;
|
bool test_mode;
|
||||||
|
bool trap_wrapping;
|
||||||
} BuildOptions;
|
} BuildOptions;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ Expr *expr_new(ExprKind kind, SourceSpan start)
|
|||||||
Expr *expr = expr_calloc();
|
Expr *expr = expr_calloc();
|
||||||
expr->expr_kind = kind;
|
expr->expr_kind = kind;
|
||||||
expr->span = start;
|
expr->span = start;
|
||||||
expr->type = NULL;
|
expr->type = expr->original_type = NULL;
|
||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,12 +170,9 @@ Expr *poisoned_expr = &poison_expr;
|
|||||||
|
|
||||||
BinaryOp binary_op[TOKEN_LAST + 1] = {
|
BinaryOp binary_op[TOKEN_LAST + 1] = {
|
||||||
[TOKEN_STAR] = BINARYOP_MULT,
|
[TOKEN_STAR] = BINARYOP_MULT,
|
||||||
[TOKEN_MULT_MOD] = BINARYOP_MULT_MOD,
|
|
||||||
[TOKEN_DIV] = BINARYOP_DIV,
|
[TOKEN_DIV] = BINARYOP_DIV,
|
||||||
[TOKEN_PLUS] = BINARYOP_ADD,
|
[TOKEN_PLUS] = BINARYOP_ADD,
|
||||||
[TOKEN_PLUS_MOD] = BINARYOP_ADD_MOD,
|
|
||||||
[TOKEN_MINUS] = BINARYOP_SUB,
|
[TOKEN_MINUS] = BINARYOP_SUB,
|
||||||
[TOKEN_MINUS_MOD] = BINARYOP_SUB_MOD,
|
|
||||||
[TOKEN_MOD] = BINARYOP_MOD,
|
[TOKEN_MOD] = BINARYOP_MOD,
|
||||||
[TOKEN_SHL] = BINARYOP_SHL,
|
[TOKEN_SHL] = BINARYOP_SHL,
|
||||||
[TOKEN_SHR] = BINARYOP_SHR,
|
[TOKEN_SHR] = BINARYOP_SHR,
|
||||||
@@ -192,13 +189,9 @@ BinaryOp binary_op[TOKEN_LAST + 1] = {
|
|||||||
[TOKEN_GREATER_EQ] = BINARYOP_GE,
|
[TOKEN_GREATER_EQ] = BINARYOP_GE,
|
||||||
[TOKEN_EQ] = BINARYOP_ASSIGN,
|
[TOKEN_EQ] = BINARYOP_ASSIGN,
|
||||||
[TOKEN_MULT_ASSIGN] = BINARYOP_MULT_ASSIGN,
|
[TOKEN_MULT_ASSIGN] = BINARYOP_MULT_ASSIGN,
|
||||||
[TOKEN_MULT_MOD_ASSIGN] = BINARYOP_MULT_MOD_ASSIGN,
|
|
||||||
[TOKEN_PLUS_ASSIGN] = BINARYOP_ADD_ASSIGN,
|
[TOKEN_PLUS_ASSIGN] = BINARYOP_ADD_ASSIGN,
|
||||||
[TOKEN_PLUS_MOD_ASSIGN] = BINARYOP_ADD_MOD_ASSIGN,
|
|
||||||
[TOKEN_MINUS_ASSIGN] = BINARYOP_SUB_ASSIGN,
|
[TOKEN_MINUS_ASSIGN] = BINARYOP_SUB_ASSIGN,
|
||||||
[TOKEN_MINUS_MOD_ASSIGN] = BINARYOP_SUB_MOD_ASSIGN,
|
|
||||||
[TOKEN_DIV_ASSIGN] = BINARYOP_DIV_ASSIGN,
|
[TOKEN_DIV_ASSIGN] = BINARYOP_DIV_ASSIGN,
|
||||||
[TOKEN_MOD_ASSIGN] = BINARYOP_MOD_ASSIGN,
|
|
||||||
[TOKEN_BIT_AND_ASSIGN] = BINARYOP_BIT_AND_ASSIGN,
|
[TOKEN_BIT_AND_ASSIGN] = BINARYOP_BIT_AND_ASSIGN,
|
||||||
[TOKEN_BIT_OR_ASSIGN] = BINARYOP_BIT_OR_ASSIGN,
|
[TOKEN_BIT_OR_ASSIGN] = BINARYOP_BIT_OR_ASSIGN,
|
||||||
[TOKEN_BIT_XOR_ASSIGN] = BINARYOP_BIT_XOR_ASSIGN,
|
[TOKEN_BIT_XOR_ASSIGN] = BINARYOP_BIT_XOR_ASSIGN,
|
||||||
@@ -209,13 +202,9 @@ BinaryOp binary_op[TOKEN_LAST + 1] = {
|
|||||||
|
|
||||||
static BinaryOp assign_binop[BINARYOP_LAST + 1] = {
|
static BinaryOp assign_binop[BINARYOP_LAST + 1] = {
|
||||||
[BINARYOP_MULT_ASSIGN] = BINARYOP_MULT,
|
[BINARYOP_MULT_ASSIGN] = BINARYOP_MULT,
|
||||||
[BINARYOP_MULT_MOD_ASSIGN] = BINARYOP_MULT_MOD,
|
|
||||||
[BINARYOP_ADD_ASSIGN] = BINARYOP_ADD,
|
[BINARYOP_ADD_ASSIGN] = BINARYOP_ADD,
|
||||||
[BINARYOP_ADD_MOD_ASSIGN] = BINARYOP_ADD_MOD,
|
|
||||||
[BINARYOP_SUB_ASSIGN] = BINARYOP_SUB,
|
[BINARYOP_SUB_ASSIGN] = BINARYOP_SUB,
|
||||||
[BINARYOP_SUB_MOD_ASSIGN] = BINARYOP_SUB_MOD,
|
|
||||||
[BINARYOP_DIV_ASSIGN] = BINARYOP_DIV,
|
[BINARYOP_DIV_ASSIGN] = BINARYOP_DIV,
|
||||||
[BINARYOP_MOD_ASSIGN] = BINARYOP_MOD,
|
|
||||||
[BINARYOP_BIT_AND_ASSIGN] = BINARYOP_BIT_AND,
|
[BINARYOP_BIT_AND_ASSIGN] = BINARYOP_BIT_AND,
|
||||||
[BINARYOP_BIT_OR_ASSIGN] = BINARYOP_BIT_OR,
|
[BINARYOP_BIT_OR_ASSIGN] = BINARYOP_BIT_OR,
|
||||||
[BINARYOP_BIT_XOR_ASSIGN] = BINARYOP_BIT_XOR,
|
[BINARYOP_BIT_XOR_ASSIGN] = BINARYOP_BIT_XOR,
|
||||||
@@ -235,7 +224,6 @@ UnaryOp unary_op[TOKEN_LAST + 1] = {
|
|||||||
[TOKEN_BIT_NOT] = UNARYOP_BITNEG,
|
[TOKEN_BIT_NOT] = UNARYOP_BITNEG,
|
||||||
[TOKEN_BANG] = UNARYOP_NOT,
|
[TOKEN_BANG] = UNARYOP_NOT,
|
||||||
[TOKEN_MINUS] = UNARYOP_NEG,
|
[TOKEN_MINUS] = UNARYOP_NEG,
|
||||||
[TOKEN_MINUS_MOD] = UNARYOP_NEGMOD,
|
|
||||||
[TOKEN_PLUSPLUS] = UNARYOP_INC,
|
[TOKEN_PLUSPLUS] = UNARYOP_INC,
|
||||||
[TOKEN_MINUSMINUS] = UNARYOP_DEC,
|
[TOKEN_MINUSMINUS] = UNARYOP_DEC,
|
||||||
};
|
};
|
||||||
@@ -397,7 +385,7 @@ void fprint_type_recursive(Context *context, FILE *file, Type *type, int indent)
|
|||||||
case TYPE_FXX:
|
case TYPE_FXX:
|
||||||
DUMP("(ct float)");
|
DUMP("(ct float)");
|
||||||
return;
|
return;
|
||||||
case TYPE_CTSTR:
|
case TYPE_STRLIT:
|
||||||
DUMP("(ct string)");
|
DUMP("(ct string)");
|
||||||
return;
|
return;
|
||||||
case TYPE_ERR_UNION:
|
case TYPE_ERR_UNION:
|
||||||
|
|||||||
@@ -765,6 +765,7 @@ struct _Expr
|
|||||||
bool reeval : 1;
|
bool reeval : 1;
|
||||||
SourceSpan span;
|
SourceSpan span;
|
||||||
Type *type;
|
Type *type;
|
||||||
|
Type *original_type;
|
||||||
union {
|
union {
|
||||||
Expr *group_expr;
|
Expr *group_expr;
|
||||||
ExprLen len_expr;
|
ExprLen len_expr;
|
||||||
@@ -1368,6 +1369,7 @@ extern Type *type_bool, *type_void, *type_compstr, *type_voidptr;
|
|||||||
extern Type *type_half, *type_float, *type_double, *type_quad;
|
extern Type *type_half, *type_float, *type_double, *type_quad;
|
||||||
extern Type *type_ichar, *type_short, *type_int, *type_long, *type_isize;
|
extern Type *type_ichar, *type_short, *type_int, *type_long, *type_isize;
|
||||||
extern Type *type_char, *type_ushort, *type_uint, *type_ulong, *type_usize;
|
extern Type *type_char, *type_ushort, *type_uint, *type_ulong, *type_usize;
|
||||||
|
extern Type *type_iptr, *type_uptr, *type_iptrdiff, *type_uptrdiff;
|
||||||
extern Type *type_u128, *type_i128;
|
extern Type *type_u128, *type_i128;
|
||||||
extern Type *type_compint, *type_compfloat;
|
extern Type *type_compint, *type_compfloat;
|
||||||
extern Type *type_c_short, *type_c_int, *type_c_long, *type_c_longlong;
|
extern Type *type_c_short, *type_c_int, *type_c_long, *type_c_longlong;
|
||||||
@@ -1438,13 +1440,8 @@ static inline bool builtin_may_negate(Type *canonical)
|
|||||||
assert(canonical->canonical == canonical);
|
assert(canonical->canonical == canonical);
|
||||||
switch (canonical->type_kind)
|
switch (canonical->type_kind)
|
||||||
{
|
{
|
||||||
case TYPE_FXX:
|
case ALL_FLOATS:
|
||||||
case TYPE_F32:
|
case ALL_SIGNED_INTS:
|
||||||
case TYPE_F64:
|
|
||||||
case TYPE_I8:
|
|
||||||
case TYPE_I16:
|
|
||||||
case TYPE_I32:
|
|
||||||
case TYPE_I64:
|
|
||||||
case TYPE_IXX:
|
case TYPE_IXX:
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
@@ -1453,12 +1450,16 @@ static inline bool builtin_may_negate(Type *canonical)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool cast_implicit(Expr *expr, Type *to_type);
|
||||||
|
bool cast(Expr *expr, Type *to_type);
|
||||||
|
bool cast_to_bool_implicit(Expr *expr);
|
||||||
|
bool cast_may_implicit(Type *from_type, Type *to_type);
|
||||||
|
bool cast_may_explicit(Type *from_type, Type *to_type);
|
||||||
|
bool cast_implicit_bit_width(Expr *expr, Type *to_type);
|
||||||
|
|
||||||
bool cast_implicit(Context *context, Expr *expr, Type *to_type);
|
|
||||||
bool cast(Context *context, Expr *expr, Type *to_type, CastType cast_type);
|
|
||||||
CastKind cast_to_bool_kind(Type *type);
|
CastKind cast_to_bool_kind(Type *type);
|
||||||
|
|
||||||
bool cast_implicitly_to_runtime(Context *context, Expr *expr);
|
bool cast_implicitly_to_runtime(Expr *expr);
|
||||||
|
|
||||||
void llvm_codegen(void *module);
|
void llvm_codegen(void *module);
|
||||||
void *llvm_gen(Context *context);
|
void *llvm_gen(Context *context);
|
||||||
@@ -1512,6 +1513,8 @@ static inline void expr_replace(Expr *expr, Expr *replacement)
|
|||||||
*expr = *replacement;
|
*expr = *replacement;
|
||||||
expr->span = loc;
|
expr->span = loc;
|
||||||
}
|
}
|
||||||
|
void expr_copy_types(Expr *to, Expr *from);
|
||||||
|
void expr_copy_properties(Expr *to, Expr *from);
|
||||||
void expr_const_set_int(ExprConst *expr, uint64_t v, TypeKind kind);
|
void expr_const_set_int(ExprConst *expr, uint64_t v, TypeKind kind);
|
||||||
void expr_const_set_float(ExprConst *expr, long double d, TypeKind kind);
|
void expr_const_set_float(ExprConst *expr, long double d, TypeKind kind);
|
||||||
void expr_const_set_bool(ExprConst *expr, bool b);
|
void expr_const_set_bool(ExprConst *expr, bool b);
|
||||||
@@ -1519,8 +1522,15 @@ void expr_const_set_null(ExprConst *expr);
|
|||||||
void expr_const_fprint(FILE *__restrict file, ExprConst *expr);
|
void expr_const_fprint(FILE *__restrict file, ExprConst *expr);
|
||||||
bool expr_const_int_overflowed(const ExprConst *expr);
|
bool expr_const_int_overflowed(const ExprConst *expr);
|
||||||
bool expr_const_compare(const ExprConst *left, const ExprConst *right, BinaryOp op);
|
bool expr_const_compare(const ExprConst *left, const ExprConst *right, BinaryOp op);
|
||||||
|
bool expr_const_will_overflow(const ExprConst *expr, TypeKind kind);
|
||||||
bool expr_is_constant_eval(Expr *expr);
|
bool expr_is_constant_eval(Expr *expr);
|
||||||
const char *expr_const_to_error_string(const ExprConst *expr);
|
const char *expr_const_to_error_string(const ExprConst *expr);
|
||||||
|
static inline void expr_set_type(Expr *expr, Type *type)
|
||||||
|
{
|
||||||
|
assert(type);
|
||||||
|
expr->type = type;
|
||||||
|
expr->original_type = type;
|
||||||
|
}
|
||||||
|
|
||||||
void fprint_decl(Context *context, FILE *file, Decl *dec);
|
void fprint_decl(Context *context, FILE *file, Decl *dec);
|
||||||
void fprint_type_info_recursive(Context *context, FILE *file, TypeInfo *type_info, int indent);
|
void fprint_type_info_recursive(Context *context, FILE *file, TypeInfo *type_info, int indent);
|
||||||
@@ -1681,12 +1691,14 @@ static inline size_t type_min_alignment(size_t a, size_t b);
|
|||||||
bool type_is_subtype(Type *type, Type *possible_subtype);
|
bool type_is_subtype(Type *type, Type *possible_subtype);
|
||||||
bool type_is_union_struct(Type *type);
|
bool type_is_union_struct(Type *type);
|
||||||
bool type_is_user_defined(Type *type);
|
bool type_is_user_defined(Type *type);
|
||||||
|
bool type_is_structurally_equivalent(Type *type1, Type *type);
|
||||||
static inline Type *type_lowering(Type *type);
|
static inline Type *type_lowering(Type *type);
|
||||||
bool type_may_have_sub_elements(Type *type);
|
bool type_may_have_sub_elements(Type *type);
|
||||||
static inline bool type_ok(Type *type);
|
static inline bool type_ok(Type *type);
|
||||||
static inline Type *type_reduced_from_expr(Expr *expr);
|
static inline Type *type_reduced_from_expr(Expr *expr);
|
||||||
ByteSize type_size(Type *type);
|
ByteSize type_size(Type *type);
|
||||||
const char *type_to_error_string(Type *type);
|
const char *type_to_error_string(Type *type);
|
||||||
|
const char *type_quoted_error_string(Type *type);
|
||||||
|
|
||||||
static inline TypeInfo *type_info_new(TypeInfoKind kind, SourceSpan span);
|
static inline TypeInfo *type_info_new(TypeInfoKind kind, SourceSpan span);
|
||||||
static inline TypeInfo *type_info_new_base(Type *type, SourceSpan span);
|
static inline TypeInfo *type_info_new_base(Type *type, SourceSpan span);
|
||||||
@@ -1706,10 +1718,20 @@ static inline Type *type_reduced_from_expr(Expr *expr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline bool type_is_pointer_sized_or_more(Type *type)
|
||||||
|
{
|
||||||
|
return type_is_integer(type) && type_size(type) >= type_size(type_iptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool type_is_pointer_sized(Type *type)
|
||||||
|
{
|
||||||
|
return type_is_integer(type) && type_size(type) == type_size(type_iptr);
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool type_is_integer(Type *type)
|
static inline bool type_is_integer(Type *type)
|
||||||
{
|
{
|
||||||
assert(type == type->canonical);
|
assert(type == type->canonical);
|
||||||
return type->type_kind >= TYPE_I8 && type->type_kind <= TYPE_U128;
|
return type->type_kind >= TYPE_I8 && type->type_kind < TYPE_IXX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1722,19 +1744,19 @@ static inline bool type_is_any_integer(Type *type)
|
|||||||
static inline bool type_is_integer_signed(Type *type)
|
static inline bool type_is_integer_signed(Type *type)
|
||||||
{
|
{
|
||||||
assert(type == type->canonical);
|
assert(type == type->canonical);
|
||||||
return type->type_kind >= TYPE_I8 && type->type_kind <= TYPE_I128;
|
return type->type_kind >= TYPE_I8 && type->type_kind < TYPE_U8;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool type_is_integer_kind(Type *type)
|
static inline bool type_is_integer_kind(Type *type)
|
||||||
{
|
{
|
||||||
assert(type == type->canonical);
|
assert(type == type->canonical);
|
||||||
return type->type_kind >= TYPE_BOOL && type->type_kind <= TYPE_U128;
|
return type->type_kind >= TYPE_BOOL && type->type_kind < TYPE_IXX;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool type_is_integer_unsigned(Type *type)
|
static inline bool type_is_integer_unsigned(Type *type)
|
||||||
{
|
{
|
||||||
assert(type == type->canonical);
|
assert(type == type->canonical);
|
||||||
return type->type_kind >= TYPE_U8 && type->type_kind <= TYPE_U128;
|
return type->type_kind >= TYPE_U8 && type->type_kind < TYPE_IXX;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool type_info_poison(TypeInfo *type)
|
static inline bool type_info_poison(TypeInfo *type)
|
||||||
@@ -1780,7 +1802,7 @@ static inline bool type_is_substruct(Type *type)
|
|||||||
static inline bool type_is_float(Type *type)
|
static inline bool type_is_float(Type *type)
|
||||||
{
|
{
|
||||||
assert(type == type->canonical);
|
assert(type == type->canonical);
|
||||||
return type->type_kind >= TYPE_F32 && type->type_kind <= TYPE_FXX;
|
return type->type_kind >= TYPE_F16 && type->type_kind <= TYPE_FXX;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline TypeInfo *type_info_new(TypeInfoKind kind, SourceSpan span)
|
static inline TypeInfo *type_info_new(TypeInfoKind kind, SourceSpan span)
|
||||||
@@ -1847,17 +1869,40 @@ static inline void advance_and_verify(Context *context, TokenType token_type)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline Type *type_flatten_distinct(Type *type)
|
||||||
|
{
|
||||||
|
type = type->canonical;
|
||||||
|
while (type->type_kind == TYPE_DISTINCT)
|
||||||
|
{
|
||||||
|
type = type->decl->distinct_decl.base_type->canonical;
|
||||||
|
}
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
static inline Type *type_flatten(Type *type)
|
static inline Type *type_flatten(Type *type)
|
||||||
{
|
{
|
||||||
type = type->canonical;
|
type = type->canonical;
|
||||||
return type->type_kind == TYPE_DISTINCT ? type->decl->distinct_decl.base_type : type;
|
while (1)
|
||||||
|
{
|
||||||
|
if (type->type_kind == TYPE_DISTINCT)
|
||||||
|
{
|
||||||
|
type = type->decl->distinct_decl.base_type;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (type->type_kind == TYPE_ENUM)
|
||||||
|
{
|
||||||
|
type = type->decl->enums.type_info->type;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return type;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
static inline bool type_is_builtin(TypeKind kind) { return kind >= TYPE_VOID && kind <= TYPE_TYPEID; }
|
static inline bool type_is_builtin(TypeKind kind) { return kind >= TYPE_VOID && kind <= TYPE_TYPEID; }
|
||||||
static inline bool type_kind_is_signed(TypeKind kind) { return kind >= TYPE_I8 && kind <= TYPE_I64; }
|
static inline bool type_kind_is_signed(TypeKind kind) { return kind >= TYPE_I8 && kind < TYPE_U8; }
|
||||||
static inline bool type_kind_is_unsigned(TypeKind kind) { return kind >= TYPE_U8 && kind <= TYPE_U64; }
|
static inline bool type_kind_is_unsigned(TypeKind kind) { return kind >= TYPE_U8 && kind < TYPE_IXX; }
|
||||||
static inline bool type_kind_is_any_integer(TypeKind kind) { return kind >= TYPE_I8 && kind <= TYPE_IXX; }
|
static inline bool type_kind_is_any_integer(TypeKind kind) { return kind >= TYPE_I8 && kind <= TYPE_IXX; }
|
||||||
static inline bool type_is_signed(Type *type) { return type->type_kind >= TYPE_I8 && type->type_kind <= TYPE_I64; }
|
static inline bool type_is_signed(Type *type) { return type->type_kind >= TYPE_I8 && type->type_kind < TYPE_U8; }
|
||||||
static inline bool type_is_unsigned(Type *type) { return type->type_kind >= TYPE_U8 && type->type_kind <= TYPE_U64; }
|
static inline bool type_is_unsigned(Type *type) { return type->type_kind >= TYPE_U8 && type->type_kind < TYPE_IXX; }
|
||||||
static inline bool type_ok(Type *type) { return !type || type->type_kind != TYPE_POISONED; }
|
static inline bool type_ok(Type *type) { return !type || type->type_kind != TYPE_POISONED; }
|
||||||
static inline bool type_info_ok(TypeInfo *type_info) { return !type_info || type_info->kind != TYPE_INFO_POISON; }
|
static inline bool type_info_ok(TypeInfo *type_info) { return !type_info || type_info->kind != TYPE_INFO_POISON; }
|
||||||
bool type_is_scalar(Type *type);
|
bool type_is_scalar(Type *type);
|
||||||
|
|||||||
@@ -8,11 +8,8 @@ typedef enum
|
|||||||
{
|
{
|
||||||
BINARYOP_ERROR,
|
BINARYOP_ERROR,
|
||||||
BINARYOP_MULT,
|
BINARYOP_MULT,
|
||||||
BINARYOP_MULT_MOD,
|
|
||||||
BINARYOP_SUB,
|
BINARYOP_SUB,
|
||||||
BINARYOP_SUB_MOD,
|
|
||||||
BINARYOP_ADD,
|
BINARYOP_ADD,
|
||||||
BINARYOP_ADD_MOD,
|
|
||||||
BINARYOP_DIV,
|
BINARYOP_DIV,
|
||||||
BINARYOP_MOD,
|
BINARYOP_MOD,
|
||||||
BINARYOP_SHR,
|
BINARYOP_SHR,
|
||||||
@@ -31,20 +28,17 @@ typedef enum
|
|||||||
BINARYOP_EQ,
|
BINARYOP_EQ,
|
||||||
// Only "assign" BINOPS after this point
|
// Only "assign" BINOPS after this point
|
||||||
BINARYOP_ASSIGN,
|
BINARYOP_ASSIGN,
|
||||||
BINARYOP_MULT_ASSIGN,
|
|
||||||
BINARYOP_MULT_MOD_ASSIGN,
|
|
||||||
BINARYOP_ADD_ASSIGN,
|
BINARYOP_ADD_ASSIGN,
|
||||||
BINARYOP_ADD_MOD_ASSIGN,
|
|
||||||
BINARYOP_SUB_ASSIGN,
|
|
||||||
BINARYOP_SUB_MOD_ASSIGN,
|
|
||||||
BINARYOP_DIV_ASSIGN,
|
|
||||||
BINARYOP_MOD_ASSIGN,
|
|
||||||
BINARYOP_BIT_AND_ASSIGN,
|
BINARYOP_BIT_AND_ASSIGN,
|
||||||
BINARYOP_BIT_OR_ASSIGN,
|
BINARYOP_BIT_OR_ASSIGN,
|
||||||
BINARYOP_BIT_XOR_ASSIGN,
|
BINARYOP_BIT_XOR_ASSIGN,
|
||||||
|
BINARYOP_DIV_ASSIGN,
|
||||||
|
BINARYOP_MOD_ASSIGN,
|
||||||
|
BINARYOP_MULT_ASSIGN,
|
||||||
BINARYOP_SHR_ASSIGN,
|
BINARYOP_SHR_ASSIGN,
|
||||||
BINARYOP_SHL_ASSIGN,
|
BINARYOP_SHL_ASSIGN,
|
||||||
BINARYOP_LAST = BINARYOP_SHL_ASSIGN
|
BINARYOP_SUB_ASSIGN,
|
||||||
|
BINARYOP_LAST = BINARYOP_SUB_ASSIGN
|
||||||
} BinaryOp;
|
} BinaryOp;
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
@@ -96,12 +90,17 @@ typedef enum
|
|||||||
CAST_XIERR,
|
CAST_XIERR,
|
||||||
CAST_PTRPTR,
|
CAST_PTRPTR,
|
||||||
CAST_PTRXI,
|
CAST_PTRXI,
|
||||||
CAST_VARRPTR,
|
CAST_PTRVAR,
|
||||||
|
CAST_VARPTR,
|
||||||
|
CAST_VARSA,
|
||||||
|
CAST_VARVAR,
|
||||||
|
CAST_VARBOOL,
|
||||||
CAST_ARRPTR,
|
CAST_ARRPTR,
|
||||||
CAST_STRPTR,
|
CAST_STRPTR,
|
||||||
CAST_PTRBOOL,
|
CAST_PTRBOOL,
|
||||||
CAST_BOOLINT,
|
CAST_BOOLINT,
|
||||||
CAST_BOOLFP,
|
CAST_BOOLFP,
|
||||||
|
CAST_BOOLBOOL,
|
||||||
CAST_FPBOOL,
|
CAST_FPBOOL,
|
||||||
CAST_INTBOOL,
|
CAST_INTBOOL,
|
||||||
CAST_CXBOOL,
|
CAST_CXBOOL,
|
||||||
@@ -118,6 +117,8 @@ typedef enum
|
|||||||
CAST_ENUMLOW,
|
CAST_ENUMLOW,
|
||||||
CAST_APTSA,
|
CAST_APTSA,
|
||||||
CAST_SAPTR,
|
CAST_SAPTR,
|
||||||
|
CAST_SABOOL,
|
||||||
|
CAST_STST,
|
||||||
} CastKind;
|
} CastKind;
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
@@ -322,15 +323,12 @@ typedef enum
|
|||||||
TOKEN_LESS_EQ, // <=
|
TOKEN_LESS_EQ, // <=
|
||||||
TOKEN_LBRAPIPE, // {|
|
TOKEN_LBRAPIPE, // {|
|
||||||
TOKEN_MINUS_ASSIGN, // -=
|
TOKEN_MINUS_ASSIGN, // -=
|
||||||
TOKEN_MINUS_MOD, // -%
|
|
||||||
TOKEN_MINUSMINUS, // --
|
TOKEN_MINUSMINUS, // --
|
||||||
TOKEN_MOD_ASSIGN, // %=
|
TOKEN_MOD_ASSIGN, // %=
|
||||||
TOKEN_MULT_ASSIGN, // *=
|
TOKEN_MULT_ASSIGN, // *=
|
||||||
TOKEN_MULT_MOD, // *%
|
|
||||||
TOKEN_NOT_EQUAL, // !=
|
TOKEN_NOT_EQUAL, // !=
|
||||||
TOKEN_OR, // ||
|
TOKEN_OR, // ||
|
||||||
TOKEN_PLUS_ASSIGN, // +=
|
TOKEN_PLUS_ASSIGN, // +=
|
||||||
TOKEN_PLUS_MOD, // +%
|
|
||||||
TOKEN_PLUSPLUS, // ++
|
TOKEN_PLUSPLUS, // ++
|
||||||
TOKEN_RBRAPIPE, // |}
|
TOKEN_RBRAPIPE, // |}
|
||||||
TOKEN_SCOPE, // ::
|
TOKEN_SCOPE, // ::
|
||||||
@@ -339,9 +337,6 @@ typedef enum
|
|||||||
|
|
||||||
// Three or more
|
// Three or more
|
||||||
TOKEN_ELLIPSIS, // ...
|
TOKEN_ELLIPSIS, // ...
|
||||||
TOKEN_MINUS_MOD_ASSIGN, // -%=
|
|
||||||
TOKEN_MULT_MOD_ASSIGN, // *%=
|
|
||||||
TOKEN_PLUS_MOD_ASSIGN, // +%=
|
|
||||||
TOKEN_SHL_ASSIGN, // <<=
|
TOKEN_SHL_ASSIGN, // <<=
|
||||||
TOKEN_SHR_ASSIGN, // >>=
|
TOKEN_SHR_ASSIGN, // >>=
|
||||||
|
|
||||||
@@ -354,27 +349,20 @@ typedef enum
|
|||||||
TOKEN_HALF,
|
TOKEN_HALF,
|
||||||
TOKEN_ICHAR,
|
TOKEN_ICHAR,
|
||||||
TOKEN_INT,
|
TOKEN_INT,
|
||||||
|
TOKEN_IPTR,
|
||||||
|
TOKEN_IPTRDIFF,
|
||||||
TOKEN_ISIZE,
|
TOKEN_ISIZE,
|
||||||
TOKEN_LONG,
|
TOKEN_LONG,
|
||||||
TOKEN_SHORT,
|
TOKEN_SHORT,
|
||||||
TOKEN_UINT,
|
TOKEN_UINT,
|
||||||
TOKEN_ULONG,
|
TOKEN_ULONG,
|
||||||
|
TOKEN_UPTR,
|
||||||
|
TOKEN_UPTRDIFF,
|
||||||
TOKEN_USHORT,
|
TOKEN_USHORT,
|
||||||
TOKEN_USIZE,
|
TOKEN_USIZE,
|
||||||
TOKEN_QUAD,
|
TOKEN_QUAD,
|
||||||
TOKEN_TYPEID,
|
TOKEN_TYPEID,
|
||||||
|
|
||||||
// C types
|
|
||||||
TOKEN_C_SHORT,
|
|
||||||
TOKEN_C_INT,
|
|
||||||
TOKEN_C_LONG,
|
|
||||||
TOKEN_C_LONGLONG,
|
|
||||||
TOKEN_C_USHORT,
|
|
||||||
TOKEN_C_UINT,
|
|
||||||
TOKEN_C_ULONG,
|
|
||||||
TOKEN_C_ULONGLONG,
|
|
||||||
|
|
||||||
|
|
||||||
// Literals.
|
// Literals.
|
||||||
TOKEN_IDENT, // Any normal ident.
|
TOKEN_IDENT, // Any normal ident.
|
||||||
TOKEN_CONST_IDENT, // Any purely upper case ident,
|
TOKEN_CONST_IDENT, // Any purely upper case ident,
|
||||||
@@ -506,7 +494,7 @@ typedef enum
|
|||||||
TYPE_ERRTYPE,
|
TYPE_ERRTYPE,
|
||||||
TYPE_ERR_UNION,
|
TYPE_ERR_UNION,
|
||||||
TYPE_TYPEDEF,
|
TYPE_TYPEDEF,
|
||||||
TYPE_CTSTR,
|
TYPE_STRLIT,
|
||||||
TYPE_DISTINCT,
|
TYPE_DISTINCT,
|
||||||
TYPE_ARRAY,
|
TYPE_ARRAY,
|
||||||
TYPE_VARARRAY,
|
TYPE_VARARRAY,
|
||||||
@@ -534,7 +522,6 @@ typedef enum
|
|||||||
UNARYOP_DEREF,
|
UNARYOP_DEREF,
|
||||||
UNARYOP_ADDR,
|
UNARYOP_ADDR,
|
||||||
UNARYOP_NEG,
|
UNARYOP_NEG,
|
||||||
UNARYOP_NEGMOD,
|
|
||||||
UNARYOP_BITNEG,
|
UNARYOP_BITNEG,
|
||||||
UNARYOP_NOT,
|
UNARYOP_NOT,
|
||||||
UNARYOP_INC,
|
UNARYOP_INC,
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ static void header_print_type(FILE *file, Type *type)
|
|||||||
break;
|
break;
|
||||||
case TYPE_TYPEDEF:
|
case TYPE_TYPEDEF:
|
||||||
break;
|
break;
|
||||||
case TYPE_CTSTR:
|
case TYPE_STRLIT:
|
||||||
case TYPE_INFERRED_ARRAY:
|
case TYPE_INFERRED_ARRAY:
|
||||||
UNREACHABLE
|
UNREACHABLE
|
||||||
case TYPE_ARRAY:
|
case TYPE_ARRAY:
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ static inline void backtrack(Lexer *lexer)
|
|||||||
void lexer_store_line_end(Lexer *lexer)
|
void lexer_store_line_end(Lexer *lexer)
|
||||||
{
|
{
|
||||||
lexer->current_line++;
|
lexer->current_line++;
|
||||||
lexer->line_start = lexer->current;
|
lexer->line_start = lexer->current + 1;
|
||||||
source_file_append_line_end(lexer->current_file, lexer->current_file->start_id + lexer->current - lexer->file_begin);
|
source_file_append_line_end(lexer->current_file, lexer->current_file->start_id + lexer->current - lexer->file_begin);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,7 +129,7 @@ static inline void add_generic_token(Lexer *lexer, TokenType type)
|
|||||||
// The simple case, where the parsing started on the current line.
|
// The simple case, where the parsing started on the current line.
|
||||||
location->line = lexer->current_line;
|
location->line = lexer->current_line;
|
||||||
// Col is simple difference.
|
// Col is simple difference.
|
||||||
location->col = (unsigned)(lexer->lexing_start - lexer->line_start);
|
location->col = (unsigned)(lexer->lexing_start - lexer->line_start) + 1;
|
||||||
// Start is offset to file begin.
|
// Start is offset to file begin.
|
||||||
location->start = lexer->lexing_start - lexer->file_begin;
|
location->start = lexer->lexing_start - lexer->file_begin;
|
||||||
// Length is diff between current and start.
|
// Length is diff between current and start.
|
||||||
@@ -1066,11 +1066,6 @@ static bool lexer_scan_token_inner(Lexer *lexer, LexMode mode)
|
|||||||
}
|
}
|
||||||
return match(lexer, '=') ? add_token(lexer, TOKEN_DIV_ASSIGN, "/=") : add_token(lexer, TOKEN_DIV, "/");
|
return match(lexer, '=') ? add_token(lexer, TOKEN_DIV_ASSIGN, "/=") : add_token(lexer, TOKEN_DIV, "/");
|
||||||
case '*':
|
case '*':
|
||||||
if (match(lexer, '%'))
|
|
||||||
{
|
|
||||||
if (match(lexer, '=')) return add_token(lexer, TOKEN_MULT_MOD_ASSIGN, "*%=");
|
|
||||||
return add_token(lexer, TOKEN_MULT_MOD, "*%");
|
|
||||||
}
|
|
||||||
return match(lexer, '=') ? add_token(lexer, TOKEN_MULT_ASSIGN, "*=") : add_token(lexer, TOKEN_STAR, "*");
|
return match(lexer, '=') ? add_token(lexer, TOKEN_MULT_ASSIGN, "*=") : add_token(lexer, TOKEN_STAR, "*");
|
||||||
case '=':
|
case '=':
|
||||||
return match(lexer, '=') ? add_token(lexer, TOKEN_EQEQ, "==") : add_token(lexer, TOKEN_EQ, "=");
|
return match(lexer, '=') ? add_token(lexer, TOKEN_EQEQ, "==") : add_token(lexer, TOKEN_EQ, "=");
|
||||||
@@ -1106,21 +1101,11 @@ static bool lexer_scan_token_inner(Lexer *lexer, LexMode mode)
|
|||||||
TOKEN_BIT_OR,
|
TOKEN_BIT_OR,
|
||||||
"|");
|
"|");
|
||||||
case '+':
|
case '+':
|
||||||
if (match(lexer, '%'))
|
|
||||||
{
|
|
||||||
if (match(lexer, '=')) return add_token(lexer, TOKEN_PLUS_MOD_ASSIGN, "+%=");
|
|
||||||
return add_token(lexer, TOKEN_PLUS_MOD, "+%");
|
|
||||||
}
|
|
||||||
if (match(lexer, '+')) return add_token(lexer, TOKEN_PLUSPLUS, "++");
|
if (match(lexer, '+')) return add_token(lexer, TOKEN_PLUSPLUS, "++");
|
||||||
if (match(lexer, '=')) return add_token(lexer, TOKEN_PLUS_ASSIGN, "+=");
|
if (match(lexer, '=')) return add_token(lexer, TOKEN_PLUS_ASSIGN, "+=");
|
||||||
return add_token(lexer, TOKEN_PLUS, "+");
|
return add_token(lexer, TOKEN_PLUS, "+");
|
||||||
case '-':
|
case '-':
|
||||||
if (match(lexer, '>')) return add_token(lexer, TOKEN_ARROW, "->");
|
if (match(lexer, '>')) return add_token(lexer, TOKEN_ARROW, "->");
|
||||||
if (match(lexer, '%'))
|
|
||||||
{
|
|
||||||
if (match(lexer, '=')) return add_token(lexer, TOKEN_MINUS_MOD_ASSIGN, "-%=");
|
|
||||||
return add_token(lexer, TOKEN_MINUS_MOD, "-%");
|
|
||||||
}
|
|
||||||
if (match(lexer, '-')) return add_token(lexer, TOKEN_MINUSMINUS, "--");
|
if (match(lexer, '-')) return add_token(lexer, TOKEN_MINUSMINUS, "--");
|
||||||
if (match(lexer, '=')) return add_token(lexer, TOKEN_MINUS_ASSIGN, "-=");
|
if (match(lexer, '=')) return add_token(lexer, TOKEN_MINUS_ASSIGN, "-=");
|
||||||
return add_token(lexer, TOKEN_MINUS, "-");
|
return add_token(lexer, TOKEN_MINUS, "-");
|
||||||
|
|||||||
@@ -315,7 +315,7 @@ void llvm_emit_ptr_from_array(GenContext *c, BEValue *value)
|
|||||||
llvm_emit_load_aligned(c, pointer_type, pointer_addr, 0, "subarrptr"), value->type, alignment);
|
llvm_emit_load_aligned(c, pointer_type, pointer_addr, 0, "subarrptr"), value->type, alignment);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case TYPE_CTSTR:
|
case TYPE_STRLIT:
|
||||||
TODO
|
TODO
|
||||||
case TYPE_VARARRAY:
|
case TYPE_VARARRAY:
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -438,7 +438,7 @@ static void x64_classify(Type *type, ByteSize offset_base, X64Class *lo_class, X
|
|||||||
case TYPE_TYPEINFO:
|
case TYPE_TYPEINFO:
|
||||||
case TYPE_MEMBER:
|
case TYPE_MEMBER:
|
||||||
case TYPE_DISTINCT:
|
case TYPE_DISTINCT:
|
||||||
case TYPE_CTSTR:
|
case TYPE_STRLIT:
|
||||||
case TYPE_INFERRED_ARRAY:
|
case TYPE_INFERRED_ARRAY:
|
||||||
UNREACHABLE
|
UNREACHABLE
|
||||||
case TYPE_VOID:
|
case TYPE_VOID:
|
||||||
@@ -632,7 +632,7 @@ AbiType *x64_get_int_type_at_offset(Type *type, unsigned offset, Type *source_ty
|
|||||||
case TYPE_TYPEINFO:
|
case TYPE_TYPEINFO:
|
||||||
case TYPE_MEMBER:
|
case TYPE_MEMBER:
|
||||||
case TYPE_DISTINCT:
|
case TYPE_DISTINCT:
|
||||||
case TYPE_CTSTR:
|
case TYPE_STRLIT:
|
||||||
case TYPE_INFERRED_ARRAY:
|
case TYPE_INFERRED_ARRAY:
|
||||||
UNREACHABLE
|
UNREACHABLE
|
||||||
case TYPE_I128:
|
case TYPE_I128:
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ static bool x86_should_return_type_in_reg(Type *type)
|
|||||||
case TYPE_TYPEINFO:
|
case TYPE_TYPEINFO:
|
||||||
case TYPE_DISTINCT:
|
case TYPE_DISTINCT:
|
||||||
case TYPE_ENUM:
|
case TYPE_ENUM:
|
||||||
case TYPE_CTSTR:
|
case TYPE_STRLIT:
|
||||||
case TYPE_INFERRED_ARRAY:
|
case TYPE_INFERRED_ARRAY:
|
||||||
UNREACHABLE
|
UNREACHABLE
|
||||||
case ALL_INTS:
|
case ALL_INTS:
|
||||||
@@ -593,7 +593,7 @@ static ABIArgInfo *x86_classify_argument(CallConvention call, Regs *regs, Type *
|
|||||||
case TYPE_DISTINCT:
|
case TYPE_DISTINCT:
|
||||||
case TYPE_FUNC:
|
case TYPE_FUNC:
|
||||||
case TYPE_TYPEID:
|
case TYPE_TYPEID:
|
||||||
case TYPE_CTSTR:
|
case TYPE_STRLIT:
|
||||||
case TYPE_INFERRED_ARRAY:
|
case TYPE_INFERRED_ARRAY:
|
||||||
UNREACHABLE
|
UNREACHABLE
|
||||||
case ALL_FLOATS:
|
case ALL_FLOATS:
|
||||||
|
|||||||
@@ -530,7 +530,7 @@ static inline LLVMMetadataRef llvm_get_debug_type_internal(GenContext *c, Type *
|
|||||||
TODO
|
TODO
|
||||||
case TYPE_TYPEDEF:
|
case TYPE_TYPEDEF:
|
||||||
return type->backend_debug_type = llvm_debug_typedef_type(c, type);
|
return type->backend_debug_type = llvm_debug_typedef_type(c, type);
|
||||||
case TYPE_CTSTR:
|
case TYPE_STRLIT:
|
||||||
TODO
|
TODO
|
||||||
case TYPE_ARRAY:
|
case TYPE_ARRAY:
|
||||||
return type->backend_debug_type = llvm_debug_array_type(c, type);
|
return type->backend_debug_type = llvm_debug_array_type(c, type);
|
||||||
|
|||||||
@@ -32,14 +32,9 @@ LLVMValueRef llvm_emit_const_padding(GenContext *c, ByteSize size)
|
|||||||
return LLVMGetUndef(llvm_const_padding_type(c, size));
|
return LLVMGetUndef(llvm_const_padding_type(c, size));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline LLVMValueRef gencontext_emit_add_int(GenContext *context, Type *type, bool use_mod, LLVMValueRef left, LLVMValueRef right)
|
static inline LLVMValueRef llvm_emit_add_int(GenContext *context, Type *type, LLVMValueRef left, LLVMValueRef right)
|
||||||
{
|
{
|
||||||
if (use_mod)
|
if (build_options.trap_wrapping)
|
||||||
{
|
|
||||||
return LLVMBuildAdd(context->builder, left, right, "add_mod");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (build_options.debug_mode)
|
|
||||||
{
|
{
|
||||||
LLVMTypeRef type_to_use = llvm_get_type(context, type->canonical);
|
LLVMTypeRef type_to_use = llvm_get_type(context, type->canonical);
|
||||||
LLVMValueRef args[2] = { left, right };
|
LLVMValueRef args[2] = { left, right };
|
||||||
@@ -58,9 +53,8 @@ static inline LLVMValueRef gencontext_emit_add_int(GenContext *context, Type *ty
|
|||||||
llvm_emit_panic_on_true(context, ok, "Addition overflow");
|
llvm_emit_panic_on_true(context, ok, "Addition overflow");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
return type_is_integer_unsigned(type)
|
|
||||||
? LLVMBuildNUWAdd(context->builder, left, right, "uadd")
|
return LLVMBuildAdd(context->builder, left, right, "add");
|
||||||
: LLVMBuildNSWAdd(context->builder, left, right, "add");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LLVMValueRef llvm_emit_coerce(GenContext *context, LLVMTypeRef coerced, BEValue *value, Type *original_type)
|
LLVMValueRef llvm_emit_coerce(GenContext *context, LLVMTypeRef coerced, BEValue *value, Type *original_type)
|
||||||
@@ -99,14 +93,10 @@ LLVMValueRef llvm_emit_convert_value_from_coerced(GenContext *context, LLVMTypeR
|
|||||||
return llvm_emit_load_aligned(context, llvm_get_type(context, original_type), temp, max_align, "coerced");
|
return llvm_emit_load_aligned(context, llvm_get_type(context, original_type), temp, max_align, "coerced");
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline LLVMValueRef gencontext_emit_sub_int(GenContext *context, Type *type, bool use_mod, LLVMValueRef left, LLVMValueRef right)
|
static inline LLVMValueRef
|
||||||
|
llvm_emit_sub_int(GenContext *context, Type *type, LLVMValueRef left, LLVMValueRef right)
|
||||||
{
|
{
|
||||||
if (use_mod)
|
if (build_options.trap_wrapping)
|
||||||
{
|
|
||||||
return LLVMBuildSub(context->builder, left, right, "sub_mod");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (build_options.debug_mode)
|
|
||||||
{
|
{
|
||||||
LLVMTypeRef type_to_use = llvm_get_type(context, type);
|
LLVMTypeRef type_to_use = llvm_get_type(context, type);
|
||||||
LLVMValueRef args[2] = { left, right };
|
LLVMValueRef args[2] = { left, right };
|
||||||
@@ -126,10 +116,7 @@ static inline LLVMValueRef gencontext_emit_sub_int(GenContext *context, Type *ty
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return LLVMBuildSub(context->builder, left, right, "sub");
|
||||||
return type_is_integer_unsigned(type)
|
|
||||||
? LLVMBuildNUWSub(context->builder, left, right, "usub")
|
|
||||||
: LLVMBuildNSWSub(context->builder, left, right, "sub");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void llvm_emit_subscript_addr_base(GenContext *context, BEValue *value, Expr *parent)
|
static inline void llvm_emit_subscript_addr_base(GenContext *context, BEValue *value, Expr *parent)
|
||||||
@@ -227,7 +214,7 @@ static inline LLVMValueRef llvm_emit_subscript_addr_with_base_new(GenContext *c,
|
|||||||
case TYPE_VARARRAY:
|
case TYPE_VARARRAY:
|
||||||
// TODO insert trap on overflow.
|
// TODO insert trap on overflow.
|
||||||
TODO
|
TODO
|
||||||
case TYPE_CTSTR:
|
case TYPE_STRLIT:
|
||||||
// TODO insert trap on overflow.
|
// TODO insert trap on overflow.
|
||||||
return LLVMBuildInBoundsGEP(c->builder, parent->value, &index->value, 1, "ptridx");
|
return LLVMBuildInBoundsGEP(c->builder, parent->value, &index->value, 1, "ptridx");
|
||||||
default:
|
default:
|
||||||
@@ -354,8 +341,11 @@ LLVMValueRef gencontext_emit_value_bitcast(GenContext *context, LLVMValueRef val
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static LLVMValueRef gencontext_emit_cast_inner(GenContext *c, CastKind cast_kind, BEValue *value, Type *to_type, Type *from_type)
|
void llvm_emit_cast(GenContext *c, CastKind cast_kind, BEValue *value, Type *to_type, Type *from_type)
|
||||||
{
|
{
|
||||||
|
to_type = type_flatten(to_type);
|
||||||
|
from_type = type_flatten(from_type);
|
||||||
|
|
||||||
switch (cast_kind)
|
switch (cast_kind)
|
||||||
{
|
{
|
||||||
case CAST_CXBOOL:
|
case CAST_CXBOOL:
|
||||||
@@ -363,7 +353,7 @@ static LLVMValueRef gencontext_emit_cast_inner(GenContext *c, CastKind cast_kind
|
|||||||
case CAST_XIERR:
|
case CAST_XIERR:
|
||||||
// TODO Insert zero check.
|
// TODO Insert zero check.
|
||||||
llvm_value_rvalue(c, value);
|
llvm_value_rvalue(c, value);
|
||||||
return value->value;
|
break;
|
||||||
case CAST_ERROR:
|
case CAST_ERROR:
|
||||||
UNREACHABLE
|
UNREACHABLE
|
||||||
case CAST_STRPTR:
|
case CAST_STRPTR:
|
||||||
@@ -371,36 +361,47 @@ static LLVMValueRef gencontext_emit_cast_inner(GenContext *c, CastKind cast_kind
|
|||||||
llvm_value_rvalue(c, value);
|
llvm_value_rvalue(c, value);
|
||||||
if (c->builder)
|
if (c->builder)
|
||||||
{
|
{
|
||||||
return LLVMBuildPointerCast(c->builder, value->value, llvm_get_type(c, to_type), "ptrptr");
|
value->value = LLVMBuildPointerCast(c->builder, value->value, llvm_get_type(c, to_type), "ptrptr");
|
||||||
}
|
}
|
||||||
return LLVMConstPointerCast(value->value, llvm_get_type(c, to_type));
|
else
|
||||||
|
{
|
||||||
|
value->value = LLVMConstPointerCast(value->value, llvm_get_type(c, to_type));
|
||||||
|
}
|
||||||
|
break;
|
||||||
case CAST_PTRXI:
|
case CAST_PTRXI:
|
||||||
llvm_value_rvalue(c, value);
|
llvm_value_rvalue(c, value);
|
||||||
if (c->builder)
|
if (c->builder)
|
||||||
{
|
{
|
||||||
return LLVMBuildPtrToInt(c->builder, value->value, llvm_get_type(c, to_type), "ptrxi");
|
value->value = LLVMBuildPtrToInt(c->builder, value->value, llvm_get_type(c, to_type), "ptrxi");
|
||||||
}
|
}
|
||||||
return LLVMConstBitCast(value->value, llvm_get_type(c, to_type));
|
else
|
||||||
|
{
|
||||||
|
value->value = LLVMConstBitCast(value->value, llvm_get_type(c, to_type));
|
||||||
|
}
|
||||||
|
break;
|
||||||
case CAST_APTSA:
|
case CAST_APTSA:
|
||||||
gencontext_emit_arr_to_subarray_cast(c, value, to_type, from_type);
|
gencontext_emit_arr_to_subarray_cast(c, value, to_type, from_type);
|
||||||
return value->value;
|
break;
|
||||||
case CAST_SAPTR:
|
case CAST_SAPTR:
|
||||||
if (llvm_value_is_addr(value))
|
if (llvm_value_is_addr(value))
|
||||||
{
|
{
|
||||||
llvm_value_fold_failable(c, value);
|
llvm_value_fold_failable(c, value);
|
||||||
return llvm_emit_load_aligned(c, llvm_get_type(c, to_type),
|
value->value = llvm_emit_load_aligned(c, llvm_get_type(c, to_type),
|
||||||
LLVMBuildStructGEP(c->builder, value->value, 0, ""),
|
LLVMBuildStructGEP(c->builder, value->value, 0, ""),
|
||||||
value->alignment, "");
|
value->alignment, "");
|
||||||
}
|
}
|
||||||
return LLVMBuildExtractValue(c->builder, value->value, 0, "");
|
else
|
||||||
case CAST_VARRPTR:
|
{
|
||||||
return value->value;
|
value->value = LLVMBuildExtractValue(c->builder, value->value, 0, "");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CAST_VARPTR:
|
||||||
|
break;
|
||||||
case CAST_ARRPTR:
|
case CAST_ARRPTR:
|
||||||
TODO
|
TODO
|
||||||
case CAST_EREU:
|
case CAST_EREU:
|
||||||
case CAST_EUER:
|
case CAST_EUER:
|
||||||
TODO
|
TODO // gencontext_emit_value_bitcast(c, value->value, to_type, from_type);
|
||||||
return gencontext_emit_value_bitcast(c, value->value, to_type, from_type);
|
|
||||||
case CAST_EUBOOL:
|
case CAST_EUBOOL:
|
||||||
if (value->kind == BE_VALUE)
|
if (value->kind == BE_VALUE)
|
||||||
{
|
{
|
||||||
@@ -415,76 +416,103 @@ static LLVMValueRef gencontext_emit_cast_inner(GenContext *c, CastKind cast_kind
|
|||||||
type_abi_alignment(type_usize),
|
type_abi_alignment(type_usize),
|
||||||
"");
|
"");
|
||||||
}
|
}
|
||||||
return LLVMBuildICmp(c->builder, LLVMIntNE, value->value, llvm_get_zero(c, type_usize), "eubool");
|
value->value = LLVMBuildICmp(c->builder, LLVMIntNE, value->value, llvm_get_zero(c, type_usize), "eubool");
|
||||||
|
value->kind = BE_BOOLEAN;
|
||||||
|
break;
|
||||||
case CAST_PTRBOOL:
|
case CAST_PTRBOOL:
|
||||||
llvm_value_rvalue(c, value);
|
llvm_value_rvalue(c, value);
|
||||||
return LLVMBuildIsNotNull(c->builder, value->value, "ptrbool");
|
value->value = LLVMBuildIsNotNull(c->builder, value->value, "ptrbool");
|
||||||
|
value->kind = BE_BOOLEAN;
|
||||||
|
break;
|
||||||
case CAST_BOOLINT:
|
case CAST_BOOLINT:
|
||||||
llvm_value_rvalue(c, value);
|
llvm_value_rvalue(c, value);
|
||||||
return LLVMBuildZExt(c->builder, value->value, llvm_get_type(c, to_type), "boolsi");
|
value->value = LLVMBuildZExt(c->builder, value->value, llvm_get_type(c, to_type), "boolsi");
|
||||||
|
value->kind = BE_VALUE;
|
||||||
|
break;
|
||||||
case CAST_FPBOOL:
|
case CAST_FPBOOL:
|
||||||
llvm_value_rvalue(c, value);
|
llvm_value_rvalue(c, value);
|
||||||
return LLVMBuildFCmp(c->builder, LLVMRealUNE, value->value, llvm_get_zero(c, from_type), "fpbool");
|
value->value = LLVMBuildFCmp(c->builder, LLVMRealUNE, value->value, llvm_get_zero(c, from_type), "fpbool");
|
||||||
|
value->kind = BE_BOOLEAN;
|
||||||
|
break;
|
||||||
case CAST_BOOLFP:
|
case CAST_BOOLFP:
|
||||||
llvm_value_rvalue(c, value);
|
llvm_value_rvalue(c, value);
|
||||||
return LLVMBuildUIToFP(c->builder, value->value, llvm_get_type(c, to_type), "boolfp");
|
value->value = LLVMBuildUIToFP(c->builder, value->value, llvm_get_type(c, to_type), "boolfp");
|
||||||
|
value->kind = BE_VALUE;
|
||||||
|
break;
|
||||||
case CAST_INTBOOL:
|
case CAST_INTBOOL:
|
||||||
llvm_value_rvalue(c, value);
|
llvm_value_rvalue(c, value);
|
||||||
return LLVMBuildICmp(c->builder, LLVMIntNE, value->value, llvm_get_zero(c, from_type), "intbool");
|
value->value = LLVMBuildICmp(c->builder, LLVMIntNE, value->value, llvm_get_zero(c, from_type), "intbool");
|
||||||
|
value->kind = BE_BOOLEAN;
|
||||||
|
break;
|
||||||
case CAST_FPFP:
|
case CAST_FPFP:
|
||||||
llvm_value_rvalue(c, value);
|
llvm_value_rvalue(c, value);
|
||||||
return type_convert_will_trunc(to_type, from_type)
|
value->value = type_convert_will_trunc(to_type, from_type)
|
||||||
? LLVMBuildFPTrunc(c->builder, value->value, llvm_get_type(c, to_type), "fpfptrunc")
|
? LLVMBuildFPTrunc(c->builder, value->value, llvm_get_type(c, to_type), "fpfptrunc")
|
||||||
: LLVMBuildFPExt(c->builder, value->value, llvm_get_type(c, to_type), "fpfpext");
|
: LLVMBuildFPExt(c->builder, value->value, llvm_get_type(c, to_type), "fpfpext");
|
||||||
|
break;
|
||||||
case CAST_FPSI:
|
case CAST_FPSI:
|
||||||
llvm_value_rvalue(c, value);
|
llvm_value_rvalue(c, value);
|
||||||
return LLVMBuildFPToSI(c->builder, value->value, llvm_get_type(c, to_type), "fpsi");
|
value->value = LLVMBuildFPToSI(c->builder, value->value, llvm_get_type(c, to_type), "fpsi");
|
||||||
|
break;
|
||||||
case CAST_FPUI:
|
case CAST_FPUI:
|
||||||
llvm_value_rvalue(c, value);
|
llvm_value_rvalue(c, value);
|
||||||
return LLVMBuildFPToUI(c->builder, value->value, llvm_get_type(c, to_type), "fpui");
|
value->value = LLVMBuildFPToUI(c->builder, value->value, llvm_get_type(c, to_type), "fpui");
|
||||||
|
break;
|
||||||
case CAST_SISI:
|
case CAST_SISI:
|
||||||
llvm_value_rvalue(c, value);
|
llvm_value_rvalue(c, value);
|
||||||
return type_convert_will_trunc(to_type, from_type)
|
value->value = type_convert_will_trunc(to_type, from_type)
|
||||||
? LLVMBuildTrunc(c->builder, value->value, llvm_get_type(c, to_type), "sisitrunc")
|
? LLVMBuildTrunc(c->builder, value->value, llvm_get_type(c, to_type), "sisitrunc")
|
||||||
: LLVMBuildSExt(c->builder, value->value, llvm_get_type(c, to_type), "sisiext");
|
: LLVMBuildSExt(c->builder, value->value, llvm_get_type(c, to_type), "sisiext");
|
||||||
|
break;
|
||||||
case CAST_SIUI:
|
case CAST_SIUI:
|
||||||
llvm_value_rvalue(c, value);
|
llvm_value_rvalue(c, value);
|
||||||
return type_convert_will_trunc(to_type, from_type)
|
value->value = type_convert_will_trunc(to_type, from_type)
|
||||||
? LLVMBuildTrunc(c->builder, value->value, llvm_get_type(c, to_type), "siuitrunc")
|
? LLVMBuildTrunc(c->builder, value->value, llvm_get_type(c, to_type), "siuitrunc")
|
||||||
: LLVMBuildZExt(c->builder, value->value, llvm_get_type(c, to_type), "siuiext");
|
: LLVMBuildZExt(c->builder, value->value, llvm_get_type(c, to_type), "siuiext");
|
||||||
|
break;
|
||||||
case CAST_SIFP:
|
case CAST_SIFP:
|
||||||
llvm_value_rvalue(c, value);
|
llvm_value_rvalue(c, value);
|
||||||
return LLVMBuildSIToFP(c->builder, value->value, llvm_get_type(c, to_type), "sifp");
|
value->value = LLVMBuildSIToFP(c->builder, value->value, llvm_get_type(c, to_type), "sifp");
|
||||||
|
break;
|
||||||
case CAST_XIPTR:
|
case CAST_XIPTR:
|
||||||
llvm_value_rvalue(c, value);
|
llvm_value_rvalue(c, value);
|
||||||
return LLVMBuildIntToPtr(c->builder, value->value, llvm_get_type(c, to_type), "xiptr");
|
value->value = LLVMBuildIntToPtr(c->builder, value->value, llvm_get_type(c, to_type), "xiptr");
|
||||||
|
break;
|
||||||
case CAST_UISI:
|
case CAST_UISI:
|
||||||
llvm_value_rvalue(c, value);
|
llvm_value_rvalue(c, value);
|
||||||
return type_convert_will_trunc(to_type, from_type)
|
value->value = type_convert_will_trunc(to_type, from_type)
|
||||||
? LLVMBuildTrunc(c->builder, value->value, llvm_get_type(c, to_type), "uisitrunc")
|
? LLVMBuildTrunc(c->builder, value->value, llvm_get_type(c, to_type), "uisitrunc")
|
||||||
: LLVMBuildZExt(c->builder, value->value, llvm_get_type(c, to_type), "uisiext");
|
: LLVMBuildZExt(c->builder, value->value, llvm_get_type(c, to_type), "uisiext");
|
||||||
|
break;
|
||||||
case CAST_UIUI:
|
case CAST_UIUI:
|
||||||
llvm_value_rvalue(c, value);
|
llvm_value_rvalue(c, value);
|
||||||
return type_convert_will_trunc(to_type, from_type)
|
value->value = type_convert_will_trunc(to_type, from_type)
|
||||||
? LLVMBuildTrunc(c->builder, value->value, llvm_get_type(c, to_type), "uiuitrunc")
|
? LLVMBuildTrunc(c->builder, value->value, llvm_get_type(c, to_type), "uiuitrunc")
|
||||||
: LLVMBuildZExt(c->builder, value->value, llvm_get_type(c, to_type), "uiuiext");
|
: LLVMBuildZExt(c->builder, value->value, llvm_get_type(c, to_type), "uiuiext");
|
||||||
|
break;
|
||||||
case CAST_UIFP:
|
case CAST_UIFP:
|
||||||
llvm_value_rvalue(c, value);
|
llvm_value_rvalue(c, value);
|
||||||
return LLVMBuildUIToFP(c->builder, value->value, llvm_get_type(c, to_type), "uifp");
|
value->value = LLVMBuildUIToFP(c->builder, value->value, llvm_get_type(c, to_type), "uifp");
|
||||||
|
break;
|
||||||
case CAST_ENUMLOW:
|
case CAST_ENUMLOW:
|
||||||
llvm_value_rvalue(c, value);
|
llvm_value_rvalue(c, value);
|
||||||
return value->value;
|
value->value = value->value;
|
||||||
|
break;
|
||||||
|
case CAST_STST:
|
||||||
|
llvm_value_addr(c, value);
|
||||||
|
value->value = LLVMBuildBitCast(c->builder, value->value, llvm_get_ptr_type(c, to_type), "");
|
||||||
|
value->type = to_type;
|
||||||
|
return;
|
||||||
|
case CAST_PTRVAR:
|
||||||
|
case CAST_VARSA:
|
||||||
|
case CAST_VARVAR:
|
||||||
|
case CAST_VARBOOL:
|
||||||
|
case CAST_BOOLBOOL:
|
||||||
|
case CAST_SABOOL:
|
||||||
|
TODO
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
UNREACHABLE
|
value->type = to_type;
|
||||||
}
|
|
||||||
|
|
||||||
void llvm_emit_cast(GenContext *c, CastKind cast_kind, BEValue *value, Type *to_type, Type *from_type)
|
|
||||||
{
|
|
||||||
to_type = type_flatten(to_type);
|
|
||||||
from_type = type_flatten(from_type);
|
|
||||||
value->value = gencontext_emit_cast_inner(c, cast_kind, value, to_type, from_type);
|
|
||||||
value->type = type_flatten(to_type);
|
|
||||||
value->kind = value->type->type_kind == TYPE_BOOL ? BE_BOOLEAN : BE_VALUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void gencontext_emit_cast_expr(GenContext *context, BEValue *be_value, Expr *expr)
|
static inline void gencontext_emit_cast_expr(GenContext *context, BEValue *be_value, Expr *expr)
|
||||||
@@ -954,8 +982,8 @@ static inline void llvm_emit_inc_dec_change(GenContext *c, bool use_mod, BEValue
|
|||||||
LLVMTypeRef llvm_type = llvm_get_type(c, type);
|
LLVMTypeRef llvm_type = llvm_get_type(c, type);
|
||||||
LLVMValueRef diff_value = LLVMConstInt(llvm_type, 1, false);
|
LLVMValueRef diff_value = LLVMConstInt(llvm_type, 1, false);
|
||||||
after_value = diff > 0
|
after_value = diff > 0
|
||||||
? gencontext_emit_add_int(c, type, use_mod, value.value, diff_value)
|
? llvm_emit_add_int(c, type, value.value, diff_value)
|
||||||
: gencontext_emit_sub_int(c, type, use_mod, value.value, diff_value);
|
: llvm_emit_sub_int(c, type, value.value, diff_value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -1036,11 +1064,6 @@ static void gencontext_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr
|
|||||||
llvm_value_rvalue(c, value);
|
llvm_value_rvalue(c, value);
|
||||||
value->value = LLVMBuildNot(c->builder, value->value, "bnot");
|
value->value = LLVMBuildNot(c->builder, value->value, "bnot");
|
||||||
return;
|
return;
|
||||||
case UNARYOP_NEGMOD:
|
|
||||||
llvm_emit_expr(c, value, expr->unary_expr.expr);
|
|
||||||
llvm_value_rvalue(c, value);
|
|
||||||
value->value = LLVMBuildNeg(c->builder, value->value, "negmod");
|
|
||||||
return;
|
|
||||||
case UNARYOP_NEG:
|
case UNARYOP_NEG:
|
||||||
llvm_emit_expr(c, value, expr->unary_expr.expr);
|
llvm_emit_expr(c, value, expr->unary_expr.expr);
|
||||||
llvm_value_rvalue(c, value);
|
llvm_value_rvalue(c, value);
|
||||||
@@ -1053,7 +1076,7 @@ static void gencontext_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr
|
|||||||
assert(!type_is_unsigned(type));
|
assert(!type_is_unsigned(type));
|
||||||
{
|
{
|
||||||
LLVMValueRef zero = llvm_get_zero(c, expr->unary_expr.expr->type);
|
LLVMValueRef zero = llvm_get_zero(c, expr->unary_expr.expr->type);
|
||||||
if (build_options.debug_mode)
|
if (build_options.trap_wrapping)
|
||||||
{
|
{
|
||||||
// TODO
|
// TODO
|
||||||
LLVMTypeRef type_to_use = llvm_get_type(c, type->canonical);
|
LLVMTypeRef type_to_use = llvm_get_type(c, type->canonical);
|
||||||
@@ -1065,7 +1088,9 @@ static void gencontext_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr
|
|||||||
llvm_emit_panic_on_true(c, ok, "Signed negation overflow");
|
llvm_emit_panic_on_true(c, ok, "Signed negation overflow");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
value->value = LLVMBuildNSWSub(c->builder, zero, value->value, "neg");
|
llvm_emit_expr(c, value, expr->unary_expr.expr);
|
||||||
|
llvm_value_rvalue(c, value);
|
||||||
|
value->value = LLVMBuildNeg(c->builder, value->value, "neg");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case UNARYOP_ADDR:
|
case UNARYOP_ADDR:
|
||||||
@@ -1109,7 +1134,7 @@ void llvm_emit_len_for_expr(GenContext *c, BEValue *be_value, BEValue *expr_to_l
|
|||||||
case TYPE_ARRAY:
|
case TYPE_ARRAY:
|
||||||
llvm_value_set(be_value, llvm_const_int(c, type_usize, expr_to_len->type->array.len), type_usize);
|
llvm_value_set(be_value, llvm_const_int(c, type_usize, expr_to_len->type->array.len), type_usize);
|
||||||
break;
|
break;
|
||||||
case TYPE_CTSTR:
|
case TYPE_STRLIT:
|
||||||
TODO
|
TODO
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -1163,7 +1188,7 @@ gencontext_emit_slice_values(GenContext *context, Expr *slice, Type **parent_typ
|
|||||||
parent_base = parent_addr;
|
parent_base = parent_addr;
|
||||||
break;
|
break;
|
||||||
case TYPE_VARARRAY:
|
case TYPE_VARARRAY:
|
||||||
case TYPE_CTSTR:
|
case TYPE_STRLIT:
|
||||||
TODO
|
TODO
|
||||||
default:
|
default:
|
||||||
UNREACHABLE
|
UNREACHABLE
|
||||||
@@ -1193,7 +1218,7 @@ gencontext_emit_slice_values(GenContext *context, Expr *slice, Type **parent_typ
|
|||||||
len = llvm_const_int(context, type_usize, parent_type->array.len);
|
len = llvm_const_int(context, type_usize, parent_type->array.len);
|
||||||
break;
|
break;
|
||||||
case TYPE_VARARRAY:
|
case TYPE_VARARRAY:
|
||||||
case TYPE_CTSTR:
|
case TYPE_STRLIT:
|
||||||
TODO
|
TODO
|
||||||
default:
|
default:
|
||||||
UNREACHABLE
|
UNREACHABLE
|
||||||
@@ -1203,7 +1228,7 @@ gencontext_emit_slice_values(GenContext *context, Expr *slice, Type **parent_typ
|
|||||||
// Walk from end if it is slice from the back.
|
// Walk from end if it is slice from the back.
|
||||||
if (slice->slice_expr.start_from_back)
|
if (slice->slice_expr.start_from_back)
|
||||||
{
|
{
|
||||||
start_index.value = gencontext_emit_sub_int(context, start_type, false, len, start_index.value);
|
start_index.value = llvm_emit_sub_int(context, start_type, len, start_index.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that index does not extend beyond the length.
|
// Check that index does not extend beyond the length.
|
||||||
@@ -1238,7 +1263,7 @@ gencontext_emit_slice_values(GenContext *context, Expr *slice, Type **parent_typ
|
|||||||
// Reverse if it is "from back"
|
// Reverse if it is "from back"
|
||||||
if (slice->slice_expr.end_from_back)
|
if (slice->slice_expr.end_from_back)
|
||||||
{
|
{
|
||||||
end_index.value = gencontext_emit_sub_int(context, end_type, false, len, end_index.value);
|
end_index.value = llvm_emit_sub_int(context, end_type, len, end_index.value);
|
||||||
llvm_value_rvalue(context, &end_index);
|
llvm_value_rvalue(context, &end_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1385,7 +1410,7 @@ static void gencontext_emit_slice_assign(GenContext *c, BEValue *be_value, Expr
|
|||||||
llvm_store_bevalue_aligned(c, target, be_value, 0);
|
llvm_store_bevalue_aligned(c, target, be_value, 0);
|
||||||
|
|
||||||
// Create the new offset
|
// Create the new offset
|
||||||
LLVMValueRef next_offset = gencontext_emit_add_int(c, start_type, false, offset, llvm_const_int(c, start_type, 1));
|
LLVMValueRef next_offset = llvm_emit_add_int(c, start_type, offset, llvm_const_int(c, start_type, 1));
|
||||||
|
|
||||||
// And jump back
|
// And jump back
|
||||||
llvm_emit_br(c, cond_block);
|
llvm_emit_br(c, cond_block);
|
||||||
@@ -1576,6 +1601,44 @@ LLVMValueRef llvm_emit_int_comparison(GenContext *c, Type *lhs_type, Type *rhs_t
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline LLVMValueRef llvm_fixup_shift_rhs(GenContext *c, LLVMValueRef left, LLVMValueRef right)
|
||||||
|
{
|
||||||
|
LLVMTypeRef left_type = LLVMTypeOf(left);
|
||||||
|
LLVMTypeRef right_type = LLVMTypeOf(right);
|
||||||
|
if (left_type == right_type) return right;
|
||||||
|
if (LLVMStoreSizeOfType(build_target.target, left_type) < LLVMStoreSizeOfType(build_target.target, right_type))
|
||||||
|
{
|
||||||
|
return LLVMBuildTrunc(c->builder, right, left_type, "");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return LLVMBuildZExt(c->builder, right, left_type, "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline LLVMValueRef llvm_emit_mult_int(GenContext *c, Type *type, LLVMValueRef left, LLVMValueRef right)
|
||||||
|
{
|
||||||
|
if (build_options.trap_wrapping)
|
||||||
|
{
|
||||||
|
LLVMTypeRef type_to_use = llvm_get_type(c, type);
|
||||||
|
LLVMValueRef args[2] = { left, right };
|
||||||
|
LLVMTypeRef types[2] = { type_to_use, type_to_use };
|
||||||
|
unsigned operation = type_is_integer_unsigned(type) ? intrinsic_id_umul_overflow
|
||||||
|
: intrinsic_id_smul_overflow;
|
||||||
|
LLVMValueRef call_res = llvm_emit_call_intrinsic(c,
|
||||||
|
operation,
|
||||||
|
types,
|
||||||
|
1,
|
||||||
|
args,
|
||||||
|
2);
|
||||||
|
LLVMValueRef val = LLVMBuildExtractValue(c->builder, call_res, 0, "mul");
|
||||||
|
LLVMValueRef ok = LLVMBuildExtractValue(c->builder, call_res, 1, "");
|
||||||
|
llvm_emit_panic_on_true(c, ok, "Integer multiplication overflow");
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
return LLVMBuildMul(c->builder, left, right, "mul");
|
||||||
|
}
|
||||||
|
|
||||||
static void gencontext_emit_binary(GenContext *c, BEValue *be_value, Expr *expr, BEValue *lhs_addr, BinaryOp binary_op)
|
static void gencontext_emit_binary(GenContext *c, BEValue *be_value, Expr *expr, BEValue *lhs_addr, BinaryOp binary_op)
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -1627,50 +1690,9 @@ static void gencontext_emit_binary(GenContext *c, BEValue *be_value, Expr *expr,
|
|||||||
val = LLVMBuildFMul(c->builder, lhs_value, rhs_value, "fmul");
|
val = LLVMBuildFMul(c->builder, lhs_value, rhs_value, "fmul");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (type_is_integer_unsigned(lhs_type))
|
val = llvm_emit_mult_int(c, lhs_type, lhs_value, rhs_value);
|
||||||
{
|
|
||||||
if (build_options.debug_mode)
|
|
||||||
{
|
|
||||||
LLVMTypeRef type_to_use = llvm_get_type(c, lhs_type);
|
|
||||||
LLVMValueRef args[2] = { lhs_value, rhs_value };
|
|
||||||
LLVMTypeRef types[2] = { type_to_use, type_to_use };
|
|
||||||
LLVMValueRef call_res = llvm_emit_call_intrinsic(c,
|
|
||||||
intrinsic_id_umul_overflow,
|
|
||||||
types,
|
|
||||||
1,
|
|
||||||
args,
|
|
||||||
2);
|
|
||||||
val = LLVMBuildExtractValue(c->builder, call_res, 0, "");
|
|
||||||
LLVMValueRef ok = LLVMBuildExtractValue(c->builder, call_res, 1, "");
|
|
||||||
llvm_emit_panic_on_true(c, ok, "Unsigned multiplication overflow");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
val = LLVMBuildNUWMul(c->builder, lhs_value, rhs_value, "umul");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (build_options.debug_mode)
|
|
||||||
{
|
|
||||||
LLVMTypeRef type_to_use = llvm_get_type(c, lhs_type);
|
|
||||||
LLVMValueRef args[2] = { lhs_value, rhs_value };
|
|
||||||
LLVMTypeRef types[2] = { type_to_use, type_to_use };
|
|
||||||
LLVMValueRef call_res = llvm_emit_call_intrinsic(c,
|
|
||||||
intrinsic_id_smul_overflow,
|
|
||||||
types,
|
|
||||||
1,
|
|
||||||
args,
|
|
||||||
2);
|
|
||||||
val = LLVMBuildExtractValue(c->builder, call_res, 0, "");
|
|
||||||
LLVMValueRef ok = LLVMBuildExtractValue(c->builder, call_res, 1, "");
|
|
||||||
llvm_emit_panic_on_true(c, ok, "Signed multiplication overflow");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
val = LLVMBuildNSWMul(c->builder, lhs_value, rhs_value, "mul");
|
|
||||||
break;
|
|
||||||
case BINARYOP_MULT_MOD:
|
|
||||||
val = LLVMBuildMul(c->builder, lhs_value, rhs_value, "mul");
|
|
||||||
break;
|
break;
|
||||||
case BINARYOP_SUB:
|
case BINARYOP_SUB:
|
||||||
case BINARYOP_SUB_MOD:
|
|
||||||
if (lhs_type->type_kind == TYPE_POINTER)
|
if (lhs_type->type_kind == TYPE_POINTER)
|
||||||
{
|
{
|
||||||
if (lhs_type == rhs_type)
|
if (lhs_type == rhs_type)
|
||||||
@@ -1687,10 +1709,9 @@ static void gencontext_emit_binary(GenContext *c, BEValue *be_value, Expr *expr,
|
|||||||
val = LLVMBuildFSub(c->builder, lhs_value, rhs_value, "fsub");
|
val = LLVMBuildFSub(c->builder, lhs_value, rhs_value, "fsub");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
val = gencontext_emit_sub_int(c, lhs_type, binary_op == BINARYOP_SUB_MOD, lhs_value, rhs_value);
|
val = llvm_emit_sub_int(c, lhs_type, lhs_value, rhs_value);
|
||||||
break;
|
break;
|
||||||
case BINARYOP_ADD:
|
case BINARYOP_ADD:
|
||||||
case BINARYOP_ADD_MOD:
|
|
||||||
if (lhs_type->type_kind == TYPE_POINTER)
|
if (lhs_type->type_kind == TYPE_POINTER)
|
||||||
{
|
{
|
||||||
assert(type_is_integer(rhs_type));
|
assert(type_is_integer(rhs_type));
|
||||||
@@ -1702,7 +1723,7 @@ static void gencontext_emit_binary(GenContext *c, BEValue *be_value, Expr *expr,
|
|||||||
val = LLVMBuildFAdd(c->builder, lhs_value, rhs_value, "fadd");
|
val = LLVMBuildFAdd(c->builder, lhs_value, rhs_value, "fadd");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
val = gencontext_emit_add_int(c, lhs_type, binary_op == BINARYOP_ADD_MOD, lhs_value, rhs_value);
|
val = llvm_emit_add_int(c, lhs_type, lhs_value, rhs_value);
|
||||||
break;
|
break;
|
||||||
case BINARYOP_DIV:
|
case BINARYOP_DIV:
|
||||||
if (is_float)
|
if (is_float)
|
||||||
@@ -1720,11 +1741,13 @@ static void gencontext_emit_binary(GenContext *c, BEValue *be_value, Expr *expr,
|
|||||||
: LLVMBuildSRem(c->builder, lhs_value, rhs_value, "smod");
|
: LLVMBuildSRem(c->builder, lhs_value, rhs_value, "smod");
|
||||||
break;
|
break;
|
||||||
case BINARYOP_SHR:
|
case BINARYOP_SHR:
|
||||||
|
rhs_value = llvm_fixup_shift_rhs(c, lhs_value, rhs_value);
|
||||||
val = type_is_unsigned(lhs_type)
|
val = type_is_unsigned(lhs_type)
|
||||||
? LLVMBuildLShr(c->builder, lhs_value, rhs_value, "lshr")
|
? LLVMBuildLShr(c->builder, lhs_value, rhs_value, "lshr")
|
||||||
: LLVMBuildAShr(c->builder, lhs_value, rhs_value, "ashr");
|
: LLVMBuildAShr(c->builder, lhs_value, rhs_value, "ashr");
|
||||||
break;
|
break;
|
||||||
case BINARYOP_SHL:
|
case BINARYOP_SHL:
|
||||||
|
rhs_value = llvm_fixup_shift_rhs(c, lhs_value, rhs_value);
|
||||||
val = LLVMBuildShl(c->builder, lhs_value, rhs_value, "shl");
|
val = LLVMBuildShl(c->builder, lhs_value, rhs_value, "shl");
|
||||||
break;
|
break;
|
||||||
case BINARYOP_BIT_AND:
|
case BINARYOP_BIT_AND:
|
||||||
@@ -1766,11 +1789,8 @@ static void gencontext_emit_binary(GenContext *c, BEValue *be_value, Expr *expr,
|
|||||||
case BINARYOP_OR:
|
case BINARYOP_OR:
|
||||||
case BINARYOP_ASSIGN:
|
case BINARYOP_ASSIGN:
|
||||||
case BINARYOP_MULT_ASSIGN:
|
case BINARYOP_MULT_ASSIGN:
|
||||||
case BINARYOP_MULT_MOD_ASSIGN:
|
|
||||||
case BINARYOP_ADD_ASSIGN:
|
case BINARYOP_ADD_ASSIGN:
|
||||||
case BINARYOP_ADD_MOD_ASSIGN:
|
|
||||||
case BINARYOP_SUB_ASSIGN:
|
case BINARYOP_SUB_ASSIGN:
|
||||||
case BINARYOP_SUB_MOD_ASSIGN:
|
|
||||||
case BINARYOP_DIV_ASSIGN:
|
case BINARYOP_DIV_ASSIGN:
|
||||||
case BINARYOP_MOD_ASSIGN:
|
case BINARYOP_MOD_ASSIGN:
|
||||||
case BINARYOP_BIT_AND_ASSIGN:
|
case BINARYOP_BIT_AND_ASSIGN:
|
||||||
@@ -2156,15 +2176,16 @@ static void llvm_emit_const_expr(GenContext *c, BEValue *be_value, Expr *expr)
|
|||||||
case TYPE_BOOL:
|
case TYPE_BOOL:
|
||||||
llvm_value_set_bool(be_value, LLVMConstInt(c->bool_type, expr->const_expr.b ? 1 : 0, 0));
|
llvm_value_set_bool(be_value, LLVMConstInt(c->bool_type, expr->const_expr.b ? 1 : 0, 0));
|
||||||
return;
|
return;
|
||||||
case TYPE_CTSTR:
|
case TYPE_STRLIT:
|
||||||
{
|
{
|
||||||
LLVMValueRef global_name = LLVMAddGlobal(c->module, LLVMArrayType(llvm_get_type(c, type_ichar), expr->const_expr.string.len + 1), "");
|
LLVMValueRef global_name = LLVMAddGlobal(c->module, LLVMArrayType(llvm_get_type(c, type_char), expr->const_expr.string.len + 1), "");
|
||||||
LLVMSetLinkage(global_name, LLVMInternalLinkage);
|
LLVMSetLinkage(global_name, LLVMInternalLinkage);
|
||||||
LLVMSetGlobalConstant(global_name, 1);
|
LLVMSetGlobalConstant(global_name, 1);
|
||||||
LLVMSetInitializer(global_name, LLVMConstStringInContext(c->context,
|
LLVMSetInitializer(global_name, LLVMConstStringInContext(c->context,
|
||||||
expr->const_expr.string.chars,
|
expr->const_expr.string.chars,
|
||||||
expr->const_expr.string.len,
|
expr->const_expr.string.len,
|
||||||
0));
|
0));
|
||||||
|
global_name = LLVMConstBitCast(global_name, LLVMPointerType(llvm_get_type(c, type_char), 0));
|
||||||
llvm_value_set(be_value, global_name, type);
|
llvm_value_set(be_value, global_name, type);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -2216,7 +2237,7 @@ static void llvm_expand_type_to_args(GenContext *context, Type *param_type, LLVM
|
|||||||
case TYPE_TYPEINFO:
|
case TYPE_TYPEINFO:
|
||||||
case TYPE_MEMBER:
|
case TYPE_MEMBER:
|
||||||
case TYPE_DISTINCT:
|
case TYPE_DISTINCT:
|
||||||
case TYPE_CTSTR:
|
case TYPE_STRLIT:
|
||||||
case TYPE_INFERRED_ARRAY:
|
case TYPE_INFERRED_ARRAY:
|
||||||
UNREACHABLE
|
UNREACHABLE
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -366,7 +366,7 @@ LLVMTypeRef llvm_get_type(GenContext *c, Type *any_type)
|
|||||||
return any_type->backend_type = LLVMIntTypeInContext(c->context, 8U);
|
return any_type->backend_type = LLVMIntTypeInContext(c->context, 8U);
|
||||||
case TYPE_POINTER:
|
case TYPE_POINTER:
|
||||||
return any_type->backend_type = llvm_type_from_ptr(c, any_type);
|
return any_type->backend_type = llvm_type_from_ptr(c, any_type);
|
||||||
case TYPE_CTSTR:
|
case TYPE_STRLIT:
|
||||||
return any_type->backend_type = LLVMPointerType(llvm_get_type(c, type_char), 0);
|
return any_type->backend_type = LLVMPointerType(llvm_get_type(c, type_char), 0);
|
||||||
case TYPE_ARRAY:
|
case TYPE_ARRAY:
|
||||||
return any_type->backend_type = llvm_type_from_array(c, any_type);
|
return any_type->backend_type = llvm_type_from_array(c, any_type);
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ void expr_const_fprint(FILE *__restrict file, ExprConst *expr)
|
|||||||
case TYPE_FXX:
|
case TYPE_FXX:
|
||||||
fprintf(file, "%Lf", expr->f);
|
fprintf(file, "%Lf", expr->f);
|
||||||
break;
|
break;
|
||||||
case TYPE_CTSTR:
|
case TYPE_STRLIT:
|
||||||
fprintf(file, "%.*s", expr->string.len, expr->string.chars);
|
fprintf(file, "%.*s", expr->string.len, expr->string.chars);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -173,7 +173,7 @@ bool expr_const_compare(const ExprConst *left, const ExprConst *right, BinaryOp
|
|||||||
return compare_fps(left->f, right->f, op);
|
return compare_fps(left->f, right->f, op);
|
||||||
case TYPE_POINTER:
|
case TYPE_POINTER:
|
||||||
return true;
|
return true;
|
||||||
case TYPE_CTSTR:
|
case TYPE_STRLIT:
|
||||||
if (left->string.len != right->string.len)
|
if (left->string.len != right->string.len)
|
||||||
{
|
{
|
||||||
is_eq = false;
|
is_eq = false;
|
||||||
@@ -193,9 +193,9 @@ bool expr_const_compare(const ExprConst *left, const ExprConst *right, BinaryOp
|
|||||||
return (op == BINARYOP_EQ) && is_eq;
|
return (op == BINARYOP_EQ) && is_eq;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool expr_const_int_overflowed(const ExprConst *expr)
|
bool expr_const_will_overflow(const ExprConst *expr, TypeKind kind)
|
||||||
{
|
{
|
||||||
switch (expr->kind)
|
switch (kind)
|
||||||
{
|
{
|
||||||
case TYPE_I8:
|
case TYPE_I8:
|
||||||
return !bigint_fits_in_bits(&expr->i, 8, true);
|
return !bigint_fits_in_bits(&expr->i, 8, true);
|
||||||
@@ -206,19 +206,31 @@ bool expr_const_int_overflowed(const ExprConst *expr)
|
|||||||
case TYPE_I64:
|
case TYPE_I64:
|
||||||
return !bigint_fits_in_bits(&expr->i, 64, true);
|
return !bigint_fits_in_bits(&expr->i, 64, true);
|
||||||
case TYPE_U8:
|
case TYPE_U8:
|
||||||
return !bigint_fits_in_bits(&expr->i, 8, false);
|
return expr->i.is_negative || !bigint_fits_in_bits(&expr->i, 8, false);
|
||||||
case TYPE_U16:
|
case TYPE_U16:
|
||||||
return !bigint_fits_in_bits(&expr->i, 16, false);
|
return expr->i.is_negative || !bigint_fits_in_bits(&expr->i, 16, false);
|
||||||
case TYPE_U32:
|
case TYPE_U32:
|
||||||
return !bigint_fits_in_bits(&expr->i, 32, false);
|
return expr->i.is_negative || !bigint_fits_in_bits(&expr->i, 32, false);
|
||||||
case TYPE_U64:
|
case TYPE_U64:
|
||||||
return !bigint_fits_in_bits(&expr->i, 64, false);
|
return expr->i.is_negative || !bigint_fits_in_bits(&expr->i, 64, false);
|
||||||
|
case TYPE_F16:
|
||||||
|
return !bigint_fits_in_bits(&expr->i, 17, false);
|
||||||
case TYPE_IXX:
|
case TYPE_IXX:
|
||||||
|
case TYPE_F32:
|
||||||
|
case TYPE_F64:
|
||||||
|
case TYPE_F128:
|
||||||
|
case TYPE_FXX:
|
||||||
|
case TYPE_BOOL:
|
||||||
return false;
|
return false;
|
||||||
default:
|
default:
|
||||||
UNREACHABLE
|
UNREACHABLE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool expr_const_int_overflowed(const ExprConst *expr)
|
||||||
|
{
|
||||||
|
return expr_const_will_overflow(expr, expr->kind);
|
||||||
|
}
|
||||||
const char *expr_const_to_error_string(const ExprConst *expr)
|
const char *expr_const_to_error_string(const ExprConst *expr)
|
||||||
{
|
{
|
||||||
char *buff = NULL;
|
char *buff = NULL;
|
||||||
@@ -243,7 +255,7 @@ const char *expr_const_to_error_string(const ExprConst *expr)
|
|||||||
case TYPE_FXX:
|
case TYPE_FXX:
|
||||||
asprintf(&buff, "%Lf", expr->f);
|
asprintf(&buff, "%Lf", expr->f);
|
||||||
return buff;
|
return buff;
|
||||||
case TYPE_CTSTR:
|
case TYPE_STRLIT:
|
||||||
asprintf(&buff, "\"%*.s\"", expr->string.len, expr->string.chars);
|
asprintf(&buff, "\"%*.s\"", expr->string.len, expr->string.chars);
|
||||||
return buff;
|
return buff;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -476,7 +476,7 @@ static Expr *parse_subscript_expr(Context *context, Expr *left)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
index = EXPR_NEW_TOKEN(EXPR_CONST, context->tok);
|
index = EXPR_NEW_TOKEN(EXPR_CONST, context->tok);
|
||||||
index->type = type_uint;
|
expr_set_type(index, type_uint);
|
||||||
index->constant = true;
|
index->constant = true;
|
||||||
index->resolve_status = RESOLVE_DONE;
|
index->resolve_status = RESOLVE_DONE;
|
||||||
expr_const_set_int(&index->const_expr, 0, type_uint->type_kind);
|
expr_const_set_int(&index->const_expr, 0, type_uint->type_kind);
|
||||||
@@ -711,7 +711,7 @@ static Expr *parse_integer(Context *context, Expr *left)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
expr_int->const_expr.kind = TYPE_IXX;
|
expr_int->const_expr.kind = TYPE_IXX;
|
||||||
expr_int->type = type_compint;
|
expr_set_type(expr_int, type_compint);
|
||||||
advance(context);
|
advance(context);
|
||||||
return expr_int;
|
return expr_int;
|
||||||
}
|
}
|
||||||
@@ -725,19 +725,19 @@ static Expr *parse_char_lit(Context *context, Expr *left)
|
|||||||
{
|
{
|
||||||
case 1:
|
case 1:
|
||||||
expr_const_set_int(&expr_int->const_expr, data->char_lit.u8, TYPE_IXX);
|
expr_const_set_int(&expr_int->const_expr, data->char_lit.u8, TYPE_IXX);
|
||||||
expr_int->type = type_compint;
|
expr_set_type(expr_int, type_compint);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
expr_const_set_int(&expr_int->const_expr, data->char_lit.u16, TYPE_IXX);
|
expr_const_set_int(&expr_int->const_expr, data->char_lit.u16, TYPE_IXX);
|
||||||
expr_int->type = type_compint;
|
expr_set_type(expr_int, type_compint);
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
expr_const_set_int(&expr_int->const_expr, data->char_lit.u32, TYPE_IXX);
|
expr_const_set_int(&expr_int->const_expr, data->char_lit.u32, TYPE_IXX);
|
||||||
expr_int->type = type_compint;
|
expr_set_type(expr_int, type_compint);
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
expr_const_set_int(&expr_int->const_expr, data->char_lit.u64, TYPE_U64);
|
expr_const_set_int(&expr_int->const_expr, data->char_lit.u64, TYPE_U64);
|
||||||
expr_int->type = type_ulong;
|
expr_set_type(expr_int, type_compint);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
UNREACHABLE
|
UNREACHABLE
|
||||||
@@ -753,7 +753,7 @@ static Expr *parse_double(Context *context, Expr *left)
|
|||||||
assert(!left && "Had left hand side");
|
assert(!left && "Had left hand side");
|
||||||
Expr *number = EXPR_NEW_TOKEN(EXPR_CONST, context->tok);
|
Expr *number = EXPR_NEW_TOKEN(EXPR_CONST, context->tok);
|
||||||
number->const_expr.f = TOKREAL(context->tok.id);
|
number->const_expr.f = TOKREAL(context->tok.id);
|
||||||
number->type = type_compfloat;
|
expr_set_type(number, type_compfloat);
|
||||||
number->const_expr.kind = TYPE_FXX;
|
number->const_expr.kind = TYPE_FXX;
|
||||||
advance(context);
|
advance(context);
|
||||||
return number;
|
return number;
|
||||||
@@ -855,7 +855,7 @@ static Expr *parse_string_literal(Context *context, Expr *left)
|
|||||||
{
|
{
|
||||||
assert(!left && "Had left hand side");
|
assert(!left && "Had left hand side");
|
||||||
Expr *expr_string = EXPR_NEW_TOKEN(EXPR_CONST, context->tok);
|
Expr *expr_string = EXPR_NEW_TOKEN(EXPR_CONST, context->tok);
|
||||||
expr_string->type = type_compstr;
|
expr_set_type(expr_string, type_compstr);
|
||||||
|
|
||||||
char *str = NULL;
|
char *str = NULL;
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
@@ -889,8 +889,8 @@ static Expr *parse_string_literal(Context *context, Expr *left)
|
|||||||
str[len] = '\0';
|
str[len] = '\0';
|
||||||
expr_string->const_expr.string.chars = str;
|
expr_string->const_expr.string.chars = str;
|
||||||
expr_string->const_expr.string.len = len;
|
expr_string->const_expr.string.len = len;
|
||||||
expr_string->type = type_compstr;
|
expr_set_type(expr_string, type_compstr);
|
||||||
expr_string->const_expr.kind = TYPE_CTSTR;
|
expr_string->const_expr.kind = TYPE_STRLIT;
|
||||||
return expr_string;
|
return expr_string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -899,7 +899,7 @@ static Expr *parse_bool(Context *context, Expr *left)
|
|||||||
assert(!left && "Had left hand side");
|
assert(!left && "Had left hand side");
|
||||||
Expr *number = EXPR_NEW_TOKEN(EXPR_CONST, context->tok);
|
Expr *number = EXPR_NEW_TOKEN(EXPR_CONST, context->tok);
|
||||||
number->const_expr = (ExprConst) { .b = TOKEN_IS(TOKEN_TRUE), .kind = TYPE_BOOL };
|
number->const_expr = (ExprConst) { .b = TOKEN_IS(TOKEN_TRUE), .kind = TYPE_BOOL };
|
||||||
number->type = type_bool;
|
expr_set_type(number, type_bool);
|
||||||
advance(context);
|
advance(context);
|
||||||
return number;
|
return number;
|
||||||
}
|
}
|
||||||
@@ -909,7 +909,7 @@ static Expr *parse_null(Context *context, Expr *left)
|
|||||||
assert(!left && "Had left hand side");
|
assert(!left && "Had left hand side");
|
||||||
Expr *number = EXPR_NEW_TOKEN(EXPR_CONST, context->tok);
|
Expr *number = EXPR_NEW_TOKEN(EXPR_CONST, context->tok);
|
||||||
number->const_expr.kind = TYPE_POINTER;
|
number->const_expr.kind = TYPE_POINTER;
|
||||||
number->type = type_voidptr;
|
expr_set_type(number, type_voidptr);
|
||||||
advance(context);
|
advance(context);
|
||||||
return number;
|
return number;
|
||||||
}
|
}
|
||||||
@@ -995,6 +995,10 @@ ParseRule rules[TOKEN_EOF + 1] = {
|
|||||||
[TOKEN_ULONG] = { parse_type_identifier, NULL, PREC_NONE },
|
[TOKEN_ULONG] = { parse_type_identifier, NULL, PREC_NONE },
|
||||||
[TOKEN_ISIZE] = { parse_type_identifier, NULL, PREC_NONE },
|
[TOKEN_ISIZE] = { parse_type_identifier, NULL, PREC_NONE },
|
||||||
[TOKEN_USIZE] = { parse_type_identifier, NULL, PREC_NONE },
|
[TOKEN_USIZE] = { parse_type_identifier, NULL, PREC_NONE },
|
||||||
|
[TOKEN_IPTR] = { parse_type_identifier, NULL, PREC_NONE },
|
||||||
|
[TOKEN_UPTR] = { parse_type_identifier, NULL, PREC_NONE },
|
||||||
|
[TOKEN_IPTRDIFF] = { parse_type_identifier, NULL, PREC_NONE },
|
||||||
|
[TOKEN_UPTRDIFF] = { parse_type_identifier, NULL, PREC_NONE },
|
||||||
[TOKEN_FLOAT] = { parse_type_identifier, NULL, PREC_NONE },
|
[TOKEN_FLOAT] = { parse_type_identifier, NULL, PREC_NONE },
|
||||||
[TOKEN_DOUBLE] = { parse_type_identifier, NULL, PREC_NONE },
|
[TOKEN_DOUBLE] = { parse_type_identifier, NULL, PREC_NONE },
|
||||||
[TOKEN_HALF] = { parse_type_identifier, NULL, PREC_NONE },
|
[TOKEN_HALF] = { parse_type_identifier, NULL, PREC_NONE },
|
||||||
@@ -1016,13 +1020,10 @@ ParseRule rules[TOKEN_EOF + 1] = {
|
|||||||
[TOKEN_BANGBANG] = { NULL, parse_bangbang_expr, PREC_CALL },
|
[TOKEN_BANGBANG] = { NULL, parse_bangbang_expr, PREC_CALL },
|
||||||
[TOKEN_LBRACKET] = { NULL, parse_subscript_expr, PREC_CALL },
|
[TOKEN_LBRACKET] = { NULL, parse_subscript_expr, PREC_CALL },
|
||||||
[TOKEN_MINUS] = { parse_unary_expr, parse_binary, PREC_ADDITIVE },
|
[TOKEN_MINUS] = { parse_unary_expr, parse_binary, PREC_ADDITIVE },
|
||||||
[TOKEN_MINUS_MOD] = { parse_unary_expr, parse_binary, PREC_ADDITIVE },
|
|
||||||
[TOKEN_PLUS] = { NULL, parse_binary, PREC_ADDITIVE },
|
[TOKEN_PLUS] = { NULL, parse_binary, PREC_ADDITIVE },
|
||||||
[TOKEN_PLUS_MOD] = { NULL, parse_binary, PREC_ADDITIVE },
|
|
||||||
[TOKEN_DIV] = { NULL, parse_binary, PREC_MULTIPLICATIVE },
|
[TOKEN_DIV] = { NULL, parse_binary, PREC_MULTIPLICATIVE },
|
||||||
[TOKEN_MOD] = { NULL, parse_binary, PREC_MULTIPLICATIVE },
|
[TOKEN_MOD] = { NULL, parse_binary, PREC_MULTIPLICATIVE },
|
||||||
[TOKEN_STAR] = { parse_unary_expr, parse_binary, PREC_MULTIPLICATIVE },
|
[TOKEN_STAR] = { parse_unary_expr, parse_binary, PREC_MULTIPLICATIVE },
|
||||||
[TOKEN_MULT_MOD] = { NULL, parse_binary, PREC_MULTIPLICATIVE },
|
|
||||||
[TOKEN_DOT] = { NULL, parse_access_expr, PREC_CALL },
|
[TOKEN_DOT] = { NULL, parse_access_expr, PREC_CALL },
|
||||||
[TOKEN_BANG] = { parse_unary_expr, parse_failable, PREC_UNARY },
|
[TOKEN_BANG] = { parse_unary_expr, parse_failable, PREC_UNARY },
|
||||||
[TOKEN_BIT_NOT] = { parse_unary_expr, NULL, PREC_UNARY },
|
[TOKEN_BIT_NOT] = { parse_unary_expr, NULL, PREC_UNARY },
|
||||||
@@ -1049,11 +1050,8 @@ ParseRule rules[TOKEN_EOF + 1] = {
|
|||||||
[TOKEN_AND] = { parse_unary_expr, parse_binary, PREC_LOGICAL },
|
[TOKEN_AND] = { parse_unary_expr, parse_binary, PREC_LOGICAL },
|
||||||
[TOKEN_EQ] = { NULL, parse_binary, PREC_ASSIGNMENT },
|
[TOKEN_EQ] = { NULL, parse_binary, PREC_ASSIGNMENT },
|
||||||
[TOKEN_PLUS_ASSIGN] = { NULL, parse_binary, PREC_ASSIGNMENT },
|
[TOKEN_PLUS_ASSIGN] = { NULL, parse_binary, PREC_ASSIGNMENT },
|
||||||
[TOKEN_PLUS_MOD_ASSIGN] = { NULL, parse_binary, PREC_ASSIGNMENT },
|
|
||||||
[TOKEN_MINUS_ASSIGN] = { NULL, parse_binary, PREC_ASSIGNMENT },
|
[TOKEN_MINUS_ASSIGN] = { NULL, parse_binary, PREC_ASSIGNMENT },
|
||||||
[TOKEN_MINUS_MOD_ASSIGN] = { NULL, parse_binary, PREC_ASSIGNMENT },
|
|
||||||
[TOKEN_MULT_ASSIGN] = { NULL, parse_binary, PREC_ASSIGNMENT },
|
[TOKEN_MULT_ASSIGN] = { NULL, parse_binary, PREC_ASSIGNMENT },
|
||||||
[TOKEN_MULT_MOD_ASSIGN] = { NULL, parse_binary, PREC_ASSIGNMENT },
|
|
||||||
[TOKEN_MOD_ASSIGN] = { NULL, parse_binary, PREC_ASSIGNMENT },
|
[TOKEN_MOD_ASSIGN] = { NULL, parse_binary, PREC_ASSIGNMENT },
|
||||||
[TOKEN_DIV_ASSIGN] = { NULL, parse_binary, PREC_ASSIGNMENT },
|
[TOKEN_DIV_ASSIGN] = { NULL, parse_binary, PREC_ASSIGNMENT },
|
||||||
[TOKEN_BIT_XOR_ASSIGN] = { NULL, parse_binary, PREC_ASSIGNMENT },
|
[TOKEN_BIT_XOR_ASSIGN] = { NULL, parse_binary, PREC_ASSIGNMENT },
|
||||||
|
|||||||
@@ -506,6 +506,12 @@ static inline TypeInfo *parse_base_type(Context *context)
|
|||||||
case TOKEN_INT:
|
case TOKEN_INT:
|
||||||
type_found = type_int;
|
type_found = type_int;
|
||||||
break;
|
break;
|
||||||
|
case TOKEN_IPTR:
|
||||||
|
type_found = type_iptr;
|
||||||
|
break;
|
||||||
|
case TOKEN_IPTRDIFF:
|
||||||
|
type_found = type_iptrdiff;
|
||||||
|
break;
|
||||||
case TOKEN_ISIZE:
|
case TOKEN_ISIZE:
|
||||||
type_found = type_isize;
|
type_found = type_isize;
|
||||||
break;
|
break;
|
||||||
@@ -521,36 +527,18 @@ static inline TypeInfo *parse_base_type(Context *context)
|
|||||||
case TOKEN_ULONG:
|
case TOKEN_ULONG:
|
||||||
type_found = type_ulong;
|
type_found = type_ulong;
|
||||||
break;
|
break;
|
||||||
|
case TOKEN_UPTR:
|
||||||
|
type_found = type_uptr;
|
||||||
|
break;
|
||||||
|
case TOKEN_UPTRDIFF:
|
||||||
|
type_found = type_uptrdiff;
|
||||||
|
break;
|
||||||
case TOKEN_USHORT:
|
case TOKEN_USHORT:
|
||||||
type_found = type_ushort;
|
type_found = type_ushort;
|
||||||
break;
|
break;
|
||||||
case TOKEN_USIZE:
|
case TOKEN_USIZE:
|
||||||
type_found = type_usize;
|
type_found = type_usize;
|
||||||
break;
|
break;
|
||||||
case TOKEN_C_SHORT:
|
|
||||||
type_found = type_c_short;
|
|
||||||
break;
|
|
||||||
case TOKEN_C_INT:
|
|
||||||
type_found = type_c_int;
|
|
||||||
break;
|
|
||||||
case TOKEN_C_LONG:
|
|
||||||
type_found = type_c_long;
|
|
||||||
break;
|
|
||||||
case TOKEN_C_LONGLONG:
|
|
||||||
type_found = type_c_longlong;
|
|
||||||
break;
|
|
||||||
case TOKEN_C_USHORT:
|
|
||||||
type_found = type_c_ushort;
|
|
||||||
break;
|
|
||||||
case TOKEN_C_UINT:
|
|
||||||
type_found = type_c_uint;
|
|
||||||
break;
|
|
||||||
case TOKEN_C_ULONG:
|
|
||||||
type_found = type_c_ulong;
|
|
||||||
break;
|
|
||||||
case TOKEN_C_ULONGLONG:
|
|
||||||
type_found = type_c_ulonglong;
|
|
||||||
break;
|
|
||||||
case TOKEN_TYPEID:
|
case TOKEN_TYPEID:
|
||||||
type_found = type_typeid;
|
type_found = type_typeid;
|
||||||
break;
|
break;
|
||||||
@@ -890,14 +878,6 @@ bool parse_next_is_decl(Context *context)
|
|||||||
case TOKEN_USHORT:
|
case TOKEN_USHORT:
|
||||||
case TOKEN_USIZE:
|
case TOKEN_USIZE:
|
||||||
case TOKEN_QUAD:
|
case TOKEN_QUAD:
|
||||||
case TOKEN_C_SHORT:
|
|
||||||
case TOKEN_C_INT:
|
|
||||||
case TOKEN_C_LONG:
|
|
||||||
case TOKEN_C_LONGLONG:
|
|
||||||
case TOKEN_C_USHORT:
|
|
||||||
case TOKEN_C_UINT:
|
|
||||||
case TOKEN_C_ULONG:
|
|
||||||
case TOKEN_C_ULONGLONG:
|
|
||||||
case TOKEN_TYPE_IDENT:
|
case TOKEN_TYPE_IDENT:
|
||||||
case TOKEN_CT_TYPE_IDENT:
|
case TOKEN_CT_TYPE_IDENT:
|
||||||
case TOKEN_ERR:
|
case TOKEN_ERR:
|
||||||
@@ -934,14 +914,6 @@ bool parse_next_is_case_type(Context *context)
|
|||||||
case TOKEN_USHORT:
|
case TOKEN_USHORT:
|
||||||
case TOKEN_USIZE:
|
case TOKEN_USIZE:
|
||||||
case TOKEN_QUAD:
|
case TOKEN_QUAD:
|
||||||
case TOKEN_C_SHORT:
|
|
||||||
case TOKEN_C_INT:
|
|
||||||
case TOKEN_C_LONG:
|
|
||||||
case TOKEN_C_LONGLONG:
|
|
||||||
case TOKEN_C_USHORT:
|
|
||||||
case TOKEN_C_UINT:
|
|
||||||
case TOKEN_C_ULONG:
|
|
||||||
case TOKEN_C_ULONGLONG:
|
|
||||||
case TOKEN_TYPE_IDENT:
|
case TOKEN_TYPE_IDENT:
|
||||||
case TOKEN_CT_TYPE_IDENT:
|
case TOKEN_CT_TYPE_IDENT:
|
||||||
case TOKEN_ERR:
|
case TOKEN_ERR:
|
||||||
|
|||||||
@@ -976,14 +976,10 @@ Ast *parse_stmt(Context *context)
|
|||||||
case TOKEN_ULONG:
|
case TOKEN_ULONG:
|
||||||
case TOKEN_USHORT:
|
case TOKEN_USHORT:
|
||||||
case TOKEN_USIZE:
|
case TOKEN_USIZE:
|
||||||
case TOKEN_C_SHORT:
|
case TOKEN_IPTRDIFF:
|
||||||
case TOKEN_C_INT:
|
case TOKEN_UPTRDIFF:
|
||||||
case TOKEN_C_LONG:
|
case TOKEN_IPTR:
|
||||||
case TOKEN_C_LONGLONG:
|
case TOKEN_UPTR:
|
||||||
case TOKEN_C_USHORT:
|
|
||||||
case TOKEN_C_UINT:
|
|
||||||
case TOKEN_C_ULONG:
|
|
||||||
case TOKEN_C_ULONGLONG:
|
|
||||||
case TOKEN_TYPEID:
|
case TOKEN_TYPEID:
|
||||||
case TOKEN_CT_TYPE_IDENT:
|
case TOKEN_CT_TYPE_IDENT:
|
||||||
case TOKEN_HASH_TYPE_IDENT:
|
case TOKEN_HASH_TYPE_IDENT:
|
||||||
@@ -1108,9 +1104,6 @@ Ast *parse_stmt(Context *context)
|
|||||||
case TOKEN_BIT_AND_ASSIGN:
|
case TOKEN_BIT_AND_ASSIGN:
|
||||||
case TOKEN_BIT_OR_ASSIGN:
|
case TOKEN_BIT_OR_ASSIGN:
|
||||||
case TOKEN_BIT_XOR_ASSIGN:
|
case TOKEN_BIT_XOR_ASSIGN:
|
||||||
case TOKEN_PLUS_MOD:
|
|
||||||
case TOKEN_MINUS_MOD:
|
|
||||||
case TOKEN_MULT_MOD:
|
|
||||||
case TOKEN_DIV_ASSIGN:
|
case TOKEN_DIV_ASSIGN:
|
||||||
case TOKEN_DOTDOT:
|
case TOKEN_DOTDOT:
|
||||||
case TOKEN_ELVIS:
|
case TOKEN_ELVIS:
|
||||||
@@ -1126,9 +1119,6 @@ Ast *parse_stmt(Context *context)
|
|||||||
case TOKEN_SCOPE:
|
case TOKEN_SCOPE:
|
||||||
case TOKEN_SHR:
|
case TOKEN_SHR:
|
||||||
case TOKEN_SHL:
|
case TOKEN_SHL:
|
||||||
case TOKEN_MULT_MOD_ASSIGN:
|
|
||||||
case TOKEN_PLUS_MOD_ASSIGN:
|
|
||||||
case TOKEN_MINUS_MOD_ASSIGN:
|
|
||||||
case TOKEN_SHR_ASSIGN:
|
case TOKEN_SHR_ASSIGN:
|
||||||
case TOKEN_SHL_ASSIGN:
|
case TOKEN_SHL_ASSIGN:
|
||||||
case TOKEN_ALIAS:
|
case TOKEN_ALIAS:
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -456,7 +456,46 @@ static inline bool sema_analyse_distinct(Context *context, Decl *decl)
|
|||||||
}
|
}
|
||||||
TypeInfo *info = decl->distinct_decl.typedef_decl.type_info;
|
TypeInfo *info = decl->distinct_decl.typedef_decl.type_info;
|
||||||
if (!sema_resolve_type_info(context, info)) return false;
|
if (!sema_resolve_type_info(context, info)) return false;
|
||||||
decl->distinct_decl.base_type = info->type->canonical;
|
Type *base = type_flatten_distinct(info->type);
|
||||||
|
decl->distinct_decl.base_type = base;
|
||||||
|
switch (base->type_kind)
|
||||||
|
{
|
||||||
|
case TYPE_POISONED:
|
||||||
|
case TYPE_STRLIT:
|
||||||
|
case TYPE_IXX:
|
||||||
|
case TYPE_FXX:
|
||||||
|
case TYPE_FUNC:
|
||||||
|
case TYPE_TYPEDEF:
|
||||||
|
case TYPE_DISTINCT:
|
||||||
|
case TYPE_INFERRED_ARRAY:
|
||||||
|
case TYPE_TYPEINFO:
|
||||||
|
case TYPE_MEMBER:
|
||||||
|
UNREACHABLE
|
||||||
|
return false;
|
||||||
|
case TYPE_ERRTYPE:
|
||||||
|
SEMA_ERROR(decl, "You cannot create a distinct type from an error.");
|
||||||
|
return false;
|
||||||
|
case TYPE_ERR_UNION:
|
||||||
|
SEMA_ERROR(decl, "You cannot create a distinct type from an error union.");
|
||||||
|
return false;
|
||||||
|
case TYPE_VOID:
|
||||||
|
case TYPE_TYPEID:
|
||||||
|
SEMA_ERROR(decl, "Cannot create a distinct type from %s.", type_quoted_error_string(base));
|
||||||
|
case TYPE_BOOL:
|
||||||
|
case ALL_SIGNED_INTS:
|
||||||
|
case ALL_UNSIGNED_INTS:
|
||||||
|
case ALL_REAL_FLOATS:
|
||||||
|
case TYPE_POINTER:
|
||||||
|
case TYPE_ENUM:
|
||||||
|
case TYPE_STRUCT:
|
||||||
|
case TYPE_UNION:
|
||||||
|
case TYPE_ARRAY:
|
||||||
|
case TYPE_VARARRAY:
|
||||||
|
case TYPE_SUBARRAY:
|
||||||
|
case TYPE_VECTOR:
|
||||||
|
case TYPE_COMPLEX:
|
||||||
|
break;
|
||||||
|
}
|
||||||
// Do we need anything else?
|
// Do we need anything else?
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -503,11 +542,11 @@ static inline bool sema_analyse_enum(Context *context, Decl *decl)
|
|||||||
if (!expr)
|
if (!expr)
|
||||||
{
|
{
|
||||||
expr = expr_new(EXPR_CONST, source_span_from_token_id(enum_value->name_token));
|
expr = expr_new(EXPR_CONST, source_span_from_token_id(enum_value->name_token));
|
||||||
expr->type = type;
|
expr_set_type(expr, type);
|
||||||
expr->resolve_status = RESOLVE_NOT_DONE;
|
expr->resolve_status = RESOLVE_NOT_DONE;
|
||||||
bigint_init_bigint(&expr->const_expr.i, &value);
|
bigint_init_bigint(&expr->const_expr.i, &value);
|
||||||
expr->const_expr.kind = TYPE_IXX;
|
expr->const_expr.kind = TYPE_IXX;
|
||||||
expr->type = type_compint;
|
expr_set_type(expr, type_compint);
|
||||||
enum_value->enum_constant.expr = expr;
|
enum_value->enum_constant.expr = expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -861,6 +900,7 @@ static inline bool sema_analyse_global(Context *context, Decl *decl)
|
|||||||
if (decl->var.init_expr && decl->type)
|
if (decl->var.init_expr && decl->type)
|
||||||
{
|
{
|
||||||
Expr *init_expr = decl->var.init_expr;
|
Expr *init_expr = decl->var.init_expr;
|
||||||
|
|
||||||
// 1. Check type.
|
// 1. Check type.
|
||||||
if (!sema_analyse_expr_of_required_type(context, decl->type, init_expr, false)) return false;
|
if (!sema_analyse_expr_of_required_type(context, decl->type, init_expr, false)) return false;
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -87,7 +87,7 @@ static Expr *context_pop_defers_and_wrap_expr(Context *context, Expr *expr)
|
|||||||
context_pop_defers_to(context, &defers);
|
context_pop_defers_to(context, &defers);
|
||||||
if (defers.end == defers.start) return expr;
|
if (defers.end == defers.start) return expr;
|
||||||
Expr *wrap = expr_new(EXPR_SCOPED_EXPR, expr->span);
|
Expr *wrap = expr_new(EXPR_SCOPED_EXPR, expr->span);
|
||||||
wrap->type = expr->type;
|
expr_copy_types(wrap, expr);
|
||||||
wrap->resolve_status = RESOLVE_DONE;
|
wrap->resolve_status = RESOLVE_DONE;
|
||||||
wrap->expr_scope.expr = expr;
|
wrap->expr_scope.expr = expr;
|
||||||
wrap->expr_scope.defers = defers;
|
wrap->expr_scope.defers = defers;
|
||||||
@@ -206,17 +206,17 @@ static inline bool sema_analyse_decl_expr_list(Context *context, Expr *expr)
|
|||||||
}
|
}
|
||||||
if (entries == 0)
|
if (entries == 0)
|
||||||
{
|
{
|
||||||
expr->type = type_void;
|
expr_set_type(expr, type_void);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
Ast *last = dexprs[entries - 1];
|
Ast *last = dexprs[entries - 1];
|
||||||
switch (last->ast_kind)
|
switch (last->ast_kind)
|
||||||
{
|
{
|
||||||
case AST_DECLARE_STMT:
|
case AST_DECLARE_STMT:
|
||||||
expr->type = last->declare_stmt->type;
|
expr_set_type(expr, last->declare_stmt->type);
|
||||||
break;
|
break;
|
||||||
case AST_EXPR_STMT:
|
case AST_EXPR_STMT:
|
||||||
expr->type = last->expr_stmt->type;
|
expr_copy_types(expr, last->expr_stmt);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
UNREACHABLE
|
UNREACHABLE
|
||||||
@@ -249,7 +249,7 @@ static inline bool sema_analyse_cond(Context *context, Expr *expr, bool cast_to_
|
|||||||
}
|
}
|
||||||
if (cast_to_bool)
|
if (cast_to_bool)
|
||||||
{
|
{
|
||||||
if (!cast_implicit(context, last->expr_stmt, type_bool)) return false;
|
if (!cast_implicit(last->expr_stmt, type_bool)) return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
case AST_DECLARE_STMT:
|
case AST_DECLARE_STMT:
|
||||||
@@ -267,8 +267,7 @@ static inline bool sema_analyse_cond(Context *context, Expr *expr, bool cast_to_
|
|||||||
type_to_error_string(last->expr_stmt->type),
|
type_to_error_string(last->expr_stmt->type),
|
||||||
cast_to_bool ? "bool" : type_to_error_string(init->type));
|
cast_to_bool ? "bool" : type_to_error_string(init->type));
|
||||||
}
|
}
|
||||||
if (!decl->var.unwrap && cast_to_bool && init->type->type_kind != TYPE_BOOL &&
|
if (!decl->var.unwrap && cast_to_bool && cast_to_bool_kind(decl->var.type_info->type) == CAST_ERROR)
|
||||||
cast_to_bool_kind(decl->var.type_info->type) == CAST_ERROR)
|
|
||||||
{
|
{
|
||||||
SEMA_ERROR(last->declare_stmt->var.init_expr, "The expression needs to be convertible to a boolean.");
|
SEMA_ERROR(last->declare_stmt->var.init_expr, "The expression needs to be convertible to a boolean.");
|
||||||
return false;
|
return false;
|
||||||
@@ -379,6 +378,11 @@ static inline bool sema_analyse_local_decl(Context *context, Decl *decl)
|
|||||||
}
|
}
|
||||||
if (!sema_expr_analyse_assign_right_side(context, NULL, decl->type, init, decl->var.failable || decl->var.unwrap ? FAILABLE_YES : FAILABLE_NO)) return decl_poison(decl);
|
if (!sema_expr_analyse_assign_right_side(context, NULL, decl->type, init, decl->var.failable || decl->var.unwrap ? FAILABLE_YES : FAILABLE_NO)) return decl_poison(decl);
|
||||||
|
|
||||||
|
if (decl->type)
|
||||||
|
{
|
||||||
|
expr_set_type(decl->var.init_expr, decl->type);
|
||||||
|
}
|
||||||
|
|
||||||
if (type_is_inferred)
|
if (type_is_inferred)
|
||||||
{
|
{
|
||||||
Type *right_side_type = init->type->canonical;
|
Type *right_side_type = init->type->canonical;
|
||||||
@@ -702,8 +706,8 @@ static inline bool sema_analyse_foreach_stmt(Context *context, Ast *statement)
|
|||||||
if (var->type != expected_var_type)
|
if (var->type != expected_var_type)
|
||||||
{
|
{
|
||||||
// This is hackish, replace when cast is refactored.
|
// This is hackish, replace when cast is refactored.
|
||||||
Expr dummy = { .resolve_status = RESOLVE_DONE, .span = { var->var.type_info->span.loc, var->span.end_loc }, .expr_kind = EXPR_IDENTIFIER, .type = expected_var_type };
|
Expr dummy = { .resolve_status = RESOLVE_DONE, .span = { var->var.type_info->span.loc, var->span.end_loc }, .expr_kind = EXPR_IDENTIFIER, .type = expected_var_type, .original_type = expected_var_type };
|
||||||
if (!cast_implicit(context, &dummy, var->type)) goto EXIT_FAIL;
|
if (!cast_implicit(&dummy, var->type)) goto EXIT_FAIL;
|
||||||
assert(dummy.expr_kind == EXPR_CAST);
|
assert(dummy.expr_kind == EXPR_CAST);
|
||||||
statement->foreach_stmt.cast = dummy.cast_expr.kind;
|
statement->foreach_stmt.cast = dummy.cast_expr.kind;
|
||||||
}
|
}
|
||||||
@@ -1003,7 +1007,7 @@ static bool sema_analyse_next_stmt(Context *context, Ast *statement)
|
|||||||
|
|
||||||
if (!sema_analyse_expr(context, parent->switch_stmt.cond->type, target)) return false;
|
if (!sema_analyse_expr(context, parent->switch_stmt.cond->type, target)) return false;
|
||||||
|
|
||||||
if (!cast_implicit(context, target, parent->switch_stmt.cond->type)) return false;
|
if (!cast_implicit(target, parent->switch_stmt.cond->type)) return false;
|
||||||
|
|
||||||
if (target->expr_kind == EXPR_CONST)
|
if (target->expr_kind == EXPR_CONST)
|
||||||
{
|
{
|
||||||
@@ -1140,7 +1144,7 @@ static bool sema_analyse_case_expr(Context *context, Type* to_type, Ast *case_st
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Type *case_type = case_expr->type->canonical;
|
Type *case_type = case_expr->original_type->canonical;
|
||||||
Type *to_type_canonical = to_type->canonical;
|
Type *to_type_canonical = to_type->canonical;
|
||||||
|
|
||||||
// 3. If we already have the same type we're done.
|
// 3. If we already have the same type we're done.
|
||||||
@@ -1148,12 +1152,12 @@ static bool sema_analyse_case_expr(Context *context, Type* to_type, Ast *case_st
|
|||||||
|
|
||||||
// 4. Otherwise check if we have an enum receiving type and a number on
|
// 4. Otherwise check if we have an enum receiving type and a number on
|
||||||
// in the case. In that case we do an implicit conversion.
|
// in the case. In that case we do an implicit conversion.
|
||||||
if (to_type_canonical->type_kind == TYPE_ENUM && type_is_any_integer(case_expr->type))
|
if (to_type_canonical->type_kind == TYPE_ENUM && type_is_any_integer(case_type))
|
||||||
{
|
{
|
||||||
return cast(context, case_expr, to_type, CAST_TYPE_EXPLICIT);
|
return cast(case_expr, to_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
return cast_implicit(context, case_expr, to_type);
|
return cast_implicit(case_expr, to_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1627,7 +1631,7 @@ bool sema_analyse_ct_assert_stmt(Context *context, Ast *statement)
|
|||||||
if (message)
|
if (message)
|
||||||
{
|
{
|
||||||
if (!sema_analyse_expr(context, type_compstr, message)) return false;
|
if (!sema_analyse_expr(context, type_compstr, message)) return false;
|
||||||
if (message->type->type_kind != TYPE_CTSTR)
|
if (message->type->type_kind != TYPE_STRLIT)
|
||||||
{
|
{
|
||||||
SEMA_ERROR(message, "Expected a string as the error message.");
|
SEMA_ERROR(message, "Expected a string as the error message.");
|
||||||
}
|
}
|
||||||
@@ -1658,7 +1662,7 @@ bool sema_analyse_assert_stmt(Context *context, Ast *statement)
|
|||||||
if (message)
|
if (message)
|
||||||
{
|
{
|
||||||
if (!sema_analyse_expr(context, type_compstr, message)) return false;
|
if (!sema_analyse_expr(context, type_compstr, message)) return false;
|
||||||
if (message->type->type_kind != TYPE_CTSTR)
|
if (message->type->type_kind != TYPE_STRLIT)
|
||||||
{
|
{
|
||||||
SEMA_ERROR(message, "Expected a string as the error message.");
|
SEMA_ERROR(message, "Expected a string as the error message.");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ static inline bool sema_resolve_array_type(Context *context, TypeInfo *type)
|
|||||||
SEMA_ERROR(type->array.len, "Expected a constant value as array size.");
|
SEMA_ERROR(type->array.len, "Expected a constant value as array size.");
|
||||||
return type_info_poison(type);
|
return type_info_poison(type);
|
||||||
}
|
}
|
||||||
if (!type_is_integer(type->array.len->type->canonical))
|
if (!type_is_any_integer(type->array.len->type->canonical))
|
||||||
{
|
{
|
||||||
SEMA_ERROR(type->array.len, "Expected an integer size.");
|
SEMA_ERROR(type->array.len, "Expected an integer size.");
|
||||||
return type_info_poison(type);
|
return type_info_poison(type);
|
||||||
|
|||||||
@@ -96,14 +96,10 @@ const char *token_type_to_string(TokenType type)
|
|||||||
return "{|";
|
return "{|";
|
||||||
case TOKEN_MINUS_ASSIGN:
|
case TOKEN_MINUS_ASSIGN:
|
||||||
return "-=";
|
return "-=";
|
||||||
case TOKEN_MINUS_MOD:
|
|
||||||
return "-%";
|
|
||||||
case TOKEN_MINUSMINUS:
|
case TOKEN_MINUSMINUS:
|
||||||
return "--";
|
return "--";
|
||||||
case TOKEN_MULT_ASSIGN:
|
case TOKEN_MULT_ASSIGN:
|
||||||
return "*=";
|
return "*=";
|
||||||
case TOKEN_MULT_MOD:
|
|
||||||
return "*%";
|
|
||||||
case TOKEN_MOD_ASSIGN:
|
case TOKEN_MOD_ASSIGN:
|
||||||
return "%=";
|
return "%=";
|
||||||
case TOKEN_NOT_EQUAL:
|
case TOKEN_NOT_EQUAL:
|
||||||
@@ -112,8 +108,6 @@ const char *token_type_to_string(TokenType type)
|
|||||||
return "||";
|
return "||";
|
||||||
case TOKEN_PLUS_ASSIGN:
|
case TOKEN_PLUS_ASSIGN:
|
||||||
return "+=";
|
return "+=";
|
||||||
case TOKEN_PLUS_MOD:
|
|
||||||
return "+%";
|
|
||||||
case TOKEN_PLUSPLUS:
|
case TOKEN_PLUSPLUS:
|
||||||
return "++";
|
return "++";
|
||||||
case TOKEN_RBRAPIPE:
|
case TOKEN_RBRAPIPE:
|
||||||
@@ -130,16 +124,10 @@ const char *token_type_to_string(TokenType type)
|
|||||||
// Three character tokens
|
// Three character tokens
|
||||||
case TOKEN_ELLIPSIS:
|
case TOKEN_ELLIPSIS:
|
||||||
return "...";
|
return "...";
|
||||||
case TOKEN_MULT_MOD_ASSIGN:
|
|
||||||
return "*%=";
|
|
||||||
case TOKEN_PLUS_MOD_ASSIGN:
|
|
||||||
return "+%=";
|
|
||||||
case TOKEN_SHL_ASSIGN:
|
case TOKEN_SHL_ASSIGN:
|
||||||
return "<<=";
|
return "<<=";
|
||||||
case TOKEN_SHR_ASSIGN:
|
case TOKEN_SHR_ASSIGN:
|
||||||
return ">>=";
|
return ">>=";
|
||||||
case TOKEN_MINUS_MOD_ASSIGN:
|
|
||||||
return "-%=";
|
|
||||||
|
|
||||||
// Identifiers
|
// Identifiers
|
||||||
case TOKEN_IDENT:
|
case TOKEN_IDENT:
|
||||||
@@ -304,27 +292,17 @@ const char *token_type_to_string(TokenType type)
|
|||||||
return "isize";
|
return "isize";
|
||||||
case TOKEN_USIZE:
|
case TOKEN_USIZE:
|
||||||
return "usize";
|
return "usize";
|
||||||
|
case TOKEN_IPTR:
|
||||||
|
return "iptr";
|
||||||
|
case TOKEN_UPTR:
|
||||||
|
return "uptr";
|
||||||
|
case TOKEN_IPTRDIFF:
|
||||||
|
return "iptrdiff";
|
||||||
|
case TOKEN_UPTRDIFF:
|
||||||
|
return "uptrdiff";
|
||||||
case TOKEN_HALF:
|
case TOKEN_HALF:
|
||||||
return "half";
|
return "half";
|
||||||
|
|
||||||
case TOKEN_C_SHORT:
|
|
||||||
return "c_short";
|
|
||||||
case TOKEN_C_INT:
|
|
||||||
return "c_int";
|
|
||||||
case TOKEN_C_LONG:
|
|
||||||
return "c_long";
|
|
||||||
case TOKEN_C_LONGLONG:
|
|
||||||
return "c_longlong";
|
|
||||||
case TOKEN_C_USHORT:
|
|
||||||
return "c_ushort";
|
|
||||||
case TOKEN_C_UINT:
|
|
||||||
return "c_uint";
|
|
||||||
case TOKEN_C_ULONG:
|
|
||||||
return "c_ulong";
|
|
||||||
case TOKEN_C_ULONGLONG:
|
|
||||||
return "c_ulonglong";
|
|
||||||
|
|
||||||
|
|
||||||
case TOKEN_DOCS_EOL:
|
case TOKEN_DOCS_EOL:
|
||||||
return "EOL";
|
return "EOL";
|
||||||
case TOKEN_DOCS_START:
|
case TOKEN_DOCS_START:
|
||||||
@@ -380,10 +358,10 @@ bool token_is_symbol(TokenType type)
|
|||||||
|
|
||||||
bool token_is_type(TokenType type)
|
bool token_is_type(TokenType type)
|
||||||
{
|
{
|
||||||
return type >= TOKEN_VOID && type <= TOKEN_C_ULONGLONG;
|
return type >= TOKEN_VOID && type <= TOKEN_TYPEID;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool token_is_any_type(TokenType type)
|
bool token_is_any_type(TokenType type)
|
||||||
{
|
{
|
||||||
return (type >= TOKEN_VOID && type <= TOKEN_C_ULONGLONG) || type == TOKEN_CT_TYPE_IDENT || type == TOKEN_TYPE_IDENT;
|
return (type >= TOKEN_VOID && type <= TOKEN_TYPEID) || type == TOKEN_CT_TYPE_IDENT || type == TOKEN_TYPE_IDENT;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
static Type t_u0, t_str, t_u1, t_i8, t_i16, t_i32, t_i64, t_i128, t_ixx;
|
static Type t_u0, t_str, t_u1, t_i8, t_i16, t_i32, t_i64, t_i128, t_ixx;
|
||||||
static Type t_u8, t_u16, t_u32, t_u64, t_u128;
|
static Type t_u8, t_u16, t_u32, t_u64, t_u128;
|
||||||
static Type t_f16, t_f32, t_f64, t_f128, t_fxx;
|
static Type t_f16, t_f32, t_f64, t_f128, t_fxx;
|
||||||
static Type t_usz, t_isz;
|
static Type t_usz, t_isz, t_uptr, t_iptr, t_uptrdiff, t_iptrdiff;
|
||||||
static Type t_cus, t_cui, t_cul, t_cull;
|
static Type t_cus, t_cui, t_cul, t_cull;
|
||||||
static Type t_cs, t_ci, t_cl, t_cll;
|
static Type t_cs, t_ci, t_cl, t_cll;
|
||||||
static Type t_voidstar, t_typeid, t_error, t_typeinfo;
|
static Type t_voidstar, t_typeid, t_error, t_typeinfo;
|
||||||
@@ -27,12 +27,16 @@ Type *type_short = &t_i16;
|
|||||||
Type *type_int = &t_i32;
|
Type *type_int = &t_i32;
|
||||||
Type *type_long = &t_i64;
|
Type *type_long = &t_i64;
|
||||||
Type *type_i128 = &t_i128;
|
Type *type_i128 = &t_i128;
|
||||||
|
Type *type_iptr = &t_iptr;
|
||||||
|
Type *type_iptrdiff = &t_iptrdiff;
|
||||||
Type *type_isize = &t_isz;
|
Type *type_isize = &t_isz;
|
||||||
Type *type_char = &t_u8;
|
Type *type_char = &t_u8;
|
||||||
Type *type_ushort = &t_u16;
|
Type *type_ushort = &t_u16;
|
||||||
Type *type_uint = &t_u32;
|
Type *type_uint = &t_u32;
|
||||||
Type *type_ulong = &t_u64;
|
Type *type_ulong = &t_u64;
|
||||||
Type *type_u128 = &t_u128;
|
Type *type_u128 = &t_u128;
|
||||||
|
Type *type_uptr = &t_uptr;
|
||||||
|
Type *type_uptrdiff = &t_uptrdiff;
|
||||||
Type *type_usize = &t_usz;
|
Type *type_usize = &t_usz;
|
||||||
Type *type_compint = &t_ixx;
|
Type *type_compint = &t_ixx;
|
||||||
Type *type_compfloat = &t_fxx;
|
Type *type_compfloat = &t_fxx;
|
||||||
@@ -83,6 +87,17 @@ Type *type_int_unsigned_by_bitsize(unsigned bytesize)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *type_quoted_error_string(Type *type)
|
||||||
|
{
|
||||||
|
char *buffer = NULL;
|
||||||
|
if (type->canonical != type)
|
||||||
|
{
|
||||||
|
asprintf(&buffer, "'%s' (%s)", type_to_error_string(type), type_to_error_string(type->canonical));
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
asprintf(&buffer, "'%s'", type_to_error_string(type));
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
const char *type_to_error_string(Type *type)
|
const char *type_to_error_string(Type *type)
|
||||||
{
|
{
|
||||||
char *buffer = NULL;
|
char *buffer = NULL;
|
||||||
@@ -129,7 +144,7 @@ const char *type_to_error_string(Type *type)
|
|||||||
}
|
}
|
||||||
asprintf(&buffer, "%s*", type_to_error_string(type->pointer));
|
asprintf(&buffer, "%s*", type_to_error_string(type->pointer));
|
||||||
return buffer;
|
return buffer;
|
||||||
case TYPE_CTSTR:
|
case TYPE_STRLIT:
|
||||||
return "compile time string";
|
return "compile time string";
|
||||||
case TYPE_ARRAY:
|
case TYPE_ARRAY:
|
||||||
asprintf(&buffer, "%s[%llu]", type_to_error_string(type->array.base), (unsigned long long)type->array.len);
|
asprintf(&buffer, "%s[%llu]", type_to_error_string(type->array.base), (unsigned long long)type->array.len);
|
||||||
@@ -208,7 +223,7 @@ ByteSize type_size(Type *type)
|
|||||||
case ALL_FLOATS:
|
case ALL_FLOATS:
|
||||||
case TYPE_ERR_UNION:
|
case TYPE_ERR_UNION:
|
||||||
return type->builtin.bytesize;
|
return type->builtin.bytesize;
|
||||||
case TYPE_CTSTR:
|
case TYPE_STRLIT:
|
||||||
case TYPE_FUNC:
|
case TYPE_FUNC:
|
||||||
case TYPE_POINTER:
|
case TYPE_POINTER:
|
||||||
case TYPE_VARARRAY:
|
case TYPE_VARARRAY:
|
||||||
@@ -338,7 +353,7 @@ bool type_is_abi_aggregate(Type *type)
|
|||||||
case TYPE_POINTER:
|
case TYPE_POINTER:
|
||||||
case TYPE_ENUM:
|
case TYPE_ENUM:
|
||||||
case TYPE_FUNC:
|
case TYPE_FUNC:
|
||||||
case TYPE_CTSTR:
|
case TYPE_STRLIT:
|
||||||
case TYPE_VECTOR:
|
case TYPE_VECTOR:
|
||||||
return false;
|
return false;
|
||||||
case TYPE_ERRTYPE:
|
case TYPE_ERRTYPE:
|
||||||
@@ -484,7 +499,7 @@ bool type_is_homogenous_aggregate(Type *type, Type **base, unsigned *elements)
|
|||||||
case TYPE_MEMBER:
|
case TYPE_MEMBER:
|
||||||
case TYPE_TYPEID:
|
case TYPE_TYPEID:
|
||||||
case TYPE_FUNC:
|
case TYPE_FUNC:
|
||||||
case TYPE_CTSTR:
|
case TYPE_STRLIT:
|
||||||
case TYPE_SUBARRAY:
|
case TYPE_SUBARRAY:
|
||||||
case TYPE_INFERRED_ARRAY:
|
case TYPE_INFERRED_ARRAY:
|
||||||
return false;
|
return false;
|
||||||
@@ -644,7 +659,7 @@ AlignSize type_abi_alignment(Type *type)
|
|||||||
case TYPE_FUNC:
|
case TYPE_FUNC:
|
||||||
case TYPE_POINTER:
|
case TYPE_POINTER:
|
||||||
case TYPE_VARARRAY:
|
case TYPE_VARARRAY:
|
||||||
case TYPE_CTSTR:
|
case TYPE_STRLIT:
|
||||||
return t_usz.canonical->builtin.abi_alignment;
|
return t_usz.canonical->builtin.abi_alignment;
|
||||||
case TYPE_ARRAY:
|
case TYPE_ARRAY:
|
||||||
return type_abi_alignment(type->array.base);
|
return type_abi_alignment(type->array.base);
|
||||||
@@ -788,6 +803,98 @@ Type *type_get_vararray(Type *arr_type)
|
|||||||
return type_generate_subarray(arr_type, false);
|
return type_generate_subarray(arr_type, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool array_structurally_equivalent_to_struct(Type *array, Type *type)
|
||||||
|
{
|
||||||
|
assert(array->type_kind == TYPE_ARRAY);
|
||||||
|
|
||||||
|
ByteSize len = array->array.len;
|
||||||
|
if (!len) return type_size(type) == 0;
|
||||||
|
|
||||||
|
Type *base = array->array.base;
|
||||||
|
|
||||||
|
if (len == 1 && type_is_structurally_equivalent(base, type)) return true;
|
||||||
|
|
||||||
|
assert(type->type_kind != TYPE_UNION && "Does not work on unions");
|
||||||
|
|
||||||
|
if (!type_is_structlike(type)) return false;
|
||||||
|
|
||||||
|
Decl **members = type->decl->strukt.members;
|
||||||
|
|
||||||
|
// For structs / errors, all members must match.
|
||||||
|
ArrayIndex offset = 0;
|
||||||
|
AlignSize align_size = type_abi_alignment(array);
|
||||||
|
Type *array_base = array->array.base;
|
||||||
|
VECEACH(members, i)
|
||||||
|
{
|
||||||
|
if (!type_is_structurally_equivalent(array_base, members[i]->type)) return false;
|
||||||
|
if (members[i]->offset != offset) return false;
|
||||||
|
offset += align_size;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool type_is_structurally_equivalent(Type *type1, Type *type2)
|
||||||
|
{
|
||||||
|
type1 = type_flatten(type1);
|
||||||
|
type2 = type_flatten(type2);
|
||||||
|
|
||||||
|
if (type1 == type2) return true;
|
||||||
|
|
||||||
|
if (type_size(type1) != type_size(type2)) return false;
|
||||||
|
|
||||||
|
// If the other type is a union, we check against every member
|
||||||
|
// noting that there is only structural equivalence if it fills out the
|
||||||
|
if (type2->type_kind == TYPE_UNION)
|
||||||
|
{
|
||||||
|
Decl **members = type2->decl->strukt.members;
|
||||||
|
// If any member is structurally equivalent, then
|
||||||
|
// the cast is valid.
|
||||||
|
VECEACH(members, i)
|
||||||
|
{
|
||||||
|
if (type_is_structurally_equivalent(type1, members[i]->type)) return true;
|
||||||
|
}
|
||||||
|
// In this case we can't get a match.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type1->type_kind == TYPE_ARRAY)
|
||||||
|
{
|
||||||
|
return array_structurally_equivalent_to_struct(type1, type2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type2->type_kind == TYPE_ARRAY)
|
||||||
|
{
|
||||||
|
return array_structurally_equivalent_to_struct(type2, type1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!type_is_structlike(type1)) return false;
|
||||||
|
|
||||||
|
Decl **members = type1->decl->strukt.members;
|
||||||
|
if (type1->type_kind == TYPE_UNION)
|
||||||
|
{
|
||||||
|
// If any member is structurally equivalent, then
|
||||||
|
// the cast is valid.
|
||||||
|
VECEACH(members, i)
|
||||||
|
{
|
||||||
|
if (type_is_structurally_equivalent(members[i]->type, type2)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The only thing we have left is to check against another structlike.
|
||||||
|
if (!type_is_structlike(type2)) return false;
|
||||||
|
|
||||||
|
Decl **other_members = type2->decl->strukt.members;
|
||||||
|
|
||||||
|
// For structs / errors, all members must match.
|
||||||
|
VECEACH(members, i)
|
||||||
|
{
|
||||||
|
if (!type_is_structurally_equivalent(members[i]->type, other_members[i]->type)) return false;
|
||||||
|
if (members[i]->offset != other_members[i]->offset) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool type_is_user_defined(Type *type)
|
bool type_is_user_defined(Type *type)
|
||||||
{
|
{
|
||||||
switch (type->type_kind)
|
switch (type->type_kind)
|
||||||
@@ -816,7 +923,7 @@ Type *type_get_indexed_type(Type *type)
|
|||||||
case TYPE_SUBARRAY:
|
case TYPE_SUBARRAY:
|
||||||
case TYPE_INFERRED_ARRAY:
|
case TYPE_INFERRED_ARRAY:
|
||||||
return type->array.base;
|
return type->array.base;
|
||||||
case TYPE_CTSTR:
|
case TYPE_STRLIT:
|
||||||
return type_char;
|
return type_char;
|
||||||
case TYPE_DISTINCT:
|
case TYPE_DISTINCT:
|
||||||
type = type->decl->distinct_decl.base_type;
|
type = type->decl->distinct_decl.base_type;
|
||||||
@@ -941,7 +1048,7 @@ type_create(#_name, &_shortname, _type, _bits, target->align_ ## _align, target-
|
|||||||
DEF_TYPE(u128, t_u128, TYPE_U128, 128, i128);
|
DEF_TYPE(u128, t_u128, TYPE_U128, 128, i128);
|
||||||
|
|
||||||
DEF_TYPE(void, t_u0, TYPE_VOID, 8, byte);
|
DEF_TYPE(void, t_u0, TYPE_VOID, 8, byte);
|
||||||
DEF_TYPE(string, t_str, TYPE_CTSTR, target->width_pointer, pointer);
|
DEF_TYPE(string, t_str, TYPE_STRLIT, target->width_pointer, pointer);
|
||||||
|
|
||||||
#undef DEF_TYPE
|
#undef DEF_TYPE
|
||||||
|
|
||||||
@@ -951,12 +1058,18 @@ type_create(#_name, &_shortname, _type, _bits, target->align_ ## _align, target-
|
|||||||
create_type_cache(type_void);
|
create_type_cache(type_void);
|
||||||
type_void->type_cache[0] = &t_voidstar;
|
type_void->type_cache[0] = &t_voidstar;
|
||||||
t_voidstar.pointer = type_void;
|
t_voidstar.pointer = type_void;
|
||||||
type_create("compint", &t_ixx, TYPE_IXX, 32, 0, 0);
|
type_create("compint", &t_ixx, TYPE_IXX, 0, 0, 0);
|
||||||
type_create("compfloat", &t_fxx, TYPE_FXX, 64, 0, 0);
|
type_create("compfloat", &t_fxx, TYPE_FXX, 0, 0, 0);
|
||||||
|
|
||||||
type_create_alias("usize", &t_usz, type_int_unsigned_by_bitsize(target->width_pointer));
|
type_create_alias("usize", &t_usz, type_int_unsigned_by_bitsize(target->width_pointer));
|
||||||
type_create_alias("isize", &t_isz, type_int_signed_by_bitsize(target->width_pointer));
|
type_create_alias("isize", &t_isz, type_int_signed_by_bitsize(target->width_pointer));
|
||||||
|
|
||||||
|
type_create_alias("uptr", &t_uptr, type_int_unsigned_by_bitsize(target->width_pointer));
|
||||||
|
type_create_alias("iptr", &t_iptr, type_int_signed_by_bitsize(target->width_pointer));
|
||||||
|
|
||||||
|
type_create_alias("uptrdiff", &t_uptrdiff, type_int_unsigned_by_bitsize(target->width_pointer));
|
||||||
|
type_create_alias("iptrdiff", &t_iptrdiff, type_int_signed_by_bitsize(target->width_pointer));
|
||||||
|
|
||||||
type_create_alias("c_ushort", &t_cus, type_int_unsigned_by_bitsize(target->width_c_short));
|
type_create_alias("c_ushort", &t_cus, type_int_unsigned_by_bitsize(target->width_c_short));
|
||||||
type_create_alias("c_uint", &t_cui, type_int_unsigned_by_bitsize(target->width_c_int));
|
type_create_alias("c_uint", &t_cui, type_int_unsigned_by_bitsize(target->width_c_int));
|
||||||
type_create_alias("c_ulong", &t_cul, type_int_unsigned_by_bitsize(target->width_c_long));
|
type_create_alias("c_ulong", &t_cul, type_int_unsigned_by_bitsize(target->width_c_long));
|
||||||
@@ -993,7 +1106,7 @@ bool type_is_scalar(Type *type)
|
|||||||
case TYPE_BOOL:
|
case TYPE_BOOL:
|
||||||
case ALL_INTS:
|
case ALL_INTS:
|
||||||
case ALL_FLOATS:
|
case ALL_FLOATS:
|
||||||
case TYPE_CTSTR:
|
case TYPE_STRLIT:
|
||||||
case TYPE_TYPEID:
|
case TYPE_TYPEID:
|
||||||
case TYPE_POINTER:
|
case TYPE_POINTER:
|
||||||
case TYPE_ENUM:
|
case TYPE_ENUM:
|
||||||
@@ -1050,52 +1163,58 @@ bool type_may_have_sub_elements(Type *type)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
L,
|
|
||||||
R,
|
|
||||||
FL,
|
|
||||||
X,
|
|
||||||
} MaxType;
|
|
||||||
|
|
||||||
Type *type_find_max_num_type(Type *num_type, Type *other_num)
|
Type *type_find_max_num_type(Type *num_type, Type *other_num)
|
||||||
{
|
{
|
||||||
TypeKind kind = num_type->type_kind;
|
TypeKind kind = num_type->type_kind;
|
||||||
TypeKind other_kind = other_num->type_kind;
|
TypeKind other_kind = other_num->type_kind;
|
||||||
|
assert(kind <= other_kind && "Expected ordering");
|
||||||
|
assert(kind != other_kind);
|
||||||
|
|
||||||
|
// 1. The only conversions need to happen if the other type is a number.
|
||||||
if (other_kind < TYPE_I8 || other_kind > TYPE_FXX) return NULL;
|
if (other_kind < TYPE_I8 || other_kind > TYPE_FXX) return NULL;
|
||||||
static MaxType max_conv[TYPE_FXX - TYPE_I8 + 1][TYPE_FXX - TYPE_I8 + 1] = {
|
|
||||||
// I8 I16 I32 I64 I128 U8 U16 U32 U64 U128 IXX F16 F32 F64 F128 FXX
|
// 2. First check the float case.
|
||||||
{ L, R, R, R, R, X, X, X, X, X, L, R, R, R, R, FL }, // I8
|
if (other_kind >= TYPE_F16 && other_kind <= TYPE_FXX)
|
||||||
{ L, L, R, R, R, L, X, X, X, X, L, R, R, R, R, FL }, // I16
|
|
||||||
{ L, L, L, R, R, L, L, X, X, X, L, R, R, R, R, FL }, // I32
|
|
||||||
{ L, L, L, L, R, L, L, L, X, X, L, R, R, R, R, FL }, // I64
|
|
||||||
{ L, L, L, L, L, L, L, L, X, X, L, R, R, R, R, FL }, // I128
|
|
||||||
{ X, R, R, R, R, L, R, R, R, R, L, R, R, R, R, FL }, // U8
|
|
||||||
{ X, X, R, R, R, L, L, R, R, R, L, R, R, R, R, FL }, // U16
|
|
||||||
{ X, X, X, R, R, L, L, L, R, R, L, R, R, R, R, FL }, // U32
|
|
||||||
{ X, X, X, X, R, L, L, L, L, R, L, R, R, R, R, FL }, // U64
|
|
||||||
{ X, X, X, X, X, L, L, L, L, L, L, R, R, R, R, FL }, // U128
|
|
||||||
{ R, R, R, R, R, R, R, R, R, R, L, R, R, R, R, R }, // IXX
|
|
||||||
{ L, L, L, L, L, L, L, L, L, L, L, L, R, R, R, L }, // F16
|
|
||||||
{ L, L, L, L, L, L, L, L, L, L, L, L, L, R, R, L }, // F32
|
|
||||||
{ L, L, L, L, L, L, L, L, L, L, L, L, L, L, R, L }, // F64
|
|
||||||
{ L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L }, // F128
|
|
||||||
{ FL, FL, FL, FL, FL, FL, FL, FL, FL, FL, FL, R, R, R, R, L }, // FXX
|
|
||||||
};
|
|
||||||
MaxType conversion = max_conv[num_type->type_kind - TYPE_I8][other_num->type_kind - TYPE_I8];
|
|
||||||
switch (conversion)
|
|
||||||
{
|
{
|
||||||
case X:
|
switch (other_kind)
|
||||||
return NULL;
|
{
|
||||||
case L:
|
case TYPE_FXX:
|
||||||
return num_type;
|
return kind <= TYPE_IXX ? type_double : other_num;
|
||||||
case R:
|
case TYPE_F16:
|
||||||
return other_num;
|
case TYPE_F32:
|
||||||
case FL:
|
case TYPE_F64:
|
||||||
return type_double;
|
case TYPE_F128:
|
||||||
default:
|
// Pick the biggest, which will be in other_num due to ordering.
|
||||||
UNREACHABLE
|
return other_num;
|
||||||
|
default:
|
||||||
|
UNREACHABLE
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle integer <=> integer conversions.
|
||||||
|
assert(type_kind_is_any_integer(other_kind) && type_is_integer(num_type));
|
||||||
|
|
||||||
|
// 3. If the other type is IXX, return the current type.
|
||||||
|
if (other_kind == TYPE_IXX) return num_type;
|
||||||
|
|
||||||
|
// 4. Check the bit sizes.
|
||||||
|
unsigned other_bit_size = other_num->builtin.bitsize;
|
||||||
|
unsigned bit_size = num_type->builtin.bitsize;
|
||||||
|
|
||||||
|
// 5. The other type is unsigned
|
||||||
|
if (type_kind_is_unsigned(other_kind))
|
||||||
|
{
|
||||||
|
if (type_kind_is_signed(kind))
|
||||||
|
{
|
||||||
|
// 5a. Signed + Unsigned -> Signed
|
||||||
|
return bit_size >= other_bit_size ? num_type : NULL;
|
||||||
|
}
|
||||||
|
// 5b. Unsigned + Unsigned -> return other_num which is the bigger due to ordering.
|
||||||
|
return other_num;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. The other type is signed, then pick other_num which is bigger due to ordering.
|
||||||
|
return other_num;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1234,7 +1353,7 @@ Type *type_find_max_type(Type *type, Type *other)
|
|||||||
TODO
|
TODO
|
||||||
case TYPE_TYPEDEF:
|
case TYPE_TYPEDEF:
|
||||||
UNREACHABLE
|
UNREACHABLE
|
||||||
case TYPE_CTSTR:
|
case TYPE_STRLIT:
|
||||||
if (other->type_kind == TYPE_DISTINCT)
|
if (other->type_kind == TYPE_DISTINCT)
|
||||||
{
|
{
|
||||||
// In this case we only react to the flattened type.
|
// In this case we only react to the flattened type.
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ static void test_lexer(void)
|
|||||||
printf("Begin lexer testing.\n");
|
printf("Begin lexer testing.\n");
|
||||||
printf("-- Check number of keywords...\n");
|
printf("-- Check number of keywords...\n");
|
||||||
int tokens_found = 0;
|
int tokens_found = 0;
|
||||||
const int EXPECTED_TOKENS = TOKEN_CT_SWITCH - TOKEN_ALIAS + 1 + TOKEN_C_ULONGLONG - TOKEN_VOID + 1;
|
const int EXPECTED_TOKENS = TOKEN_CT_SWITCH - TOKEN_ALIAS + 1 + TOKEN_TYPEID - TOKEN_VOID + 1;
|
||||||
const char* tokens[TOKEN_EOF];
|
const char* tokens[TOKEN_EOF];
|
||||||
int len[TOKEN_EOF];
|
int len[TOKEN_EOF];
|
||||||
Lexer lexer;
|
Lexer lexer;
|
||||||
|
|||||||
@@ -8,5 +8,5 @@ func void test()
|
|||||||
func void test2()
|
func void test2()
|
||||||
{
|
{
|
||||||
int[3] x;
|
int[3] x;
|
||||||
double[] z = &x; // #error: Cannot cast 'int[3]*' to 'double[]'
|
double[] z = &x; // #error: Cannot implicitly cast 'int[3]*' to 'double[]'
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
usize z = -1; // #error: Negative number '-1'
|
int[-1] a; // #error: An array may not have a negative size
|
||||||
int[-1] a; // #error: Negative number '-1'
|
int[10-20] b; // #error: An array may not have a negative size
|
||||||
int[10-20] b; // #error: '-10' underflows type 'ulong'
|
|
||||||
@@ -31,6 +31,6 @@ if.exit:
|
|||||||
|
|
||||||
unreachable_block:
|
unreachable_block:
|
||||||
%2 = load i32, i32* %x
|
%2 = load i32, i32* %x
|
||||||
%add = add nsw i32 %2, 1
|
%add = add i32 %2, 1
|
||||||
store i32 %add, i32* %x
|
store i32 %add, i32* %x
|
||||||
ret void
|
ret void
|
||||||
|
|||||||
37
test/test_suite/cast/cast_struct.c3
Normal file
37
test/test_suite/cast/cast_struct.c3
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
struct Foo
|
||||||
|
{
|
||||||
|
int a;
|
||||||
|
float b;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Bar
|
||||||
|
{
|
||||||
|
int b;
|
||||||
|
float c;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Baz
|
||||||
|
{
|
||||||
|
int b;
|
||||||
|
int c;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct BazTwo
|
||||||
|
{
|
||||||
|
int[1] d;
|
||||||
|
int e;
|
||||||
|
}
|
||||||
|
|
||||||
|
func void test()
|
||||||
|
{
|
||||||
|
Foo x;
|
||||||
|
Bar y = cast(x as Bar);
|
||||||
|
|
||||||
|
Baz z;
|
||||||
|
int[2] w = cast(z as int[2]);
|
||||||
|
z = cast(w as Baz);
|
||||||
|
BazTwo v = cast(z as BazTwo);
|
||||||
|
v = cast(w as BazTwo);
|
||||||
|
z = cast(v as Baz);
|
||||||
|
w = cast(v as int[2]);
|
||||||
|
}
|
||||||
34
test/test_suite/cast/cast_struct_fails.c3
Normal file
34
test/test_suite/cast/cast_struct_fails.c3
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
struct Foo
|
||||||
|
{
|
||||||
|
int a;
|
||||||
|
float b;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Bar
|
||||||
|
{
|
||||||
|
int b;
|
||||||
|
float c;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Baz
|
||||||
|
{
|
||||||
|
int b;
|
||||||
|
int c;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct BazTwo
|
||||||
|
{
|
||||||
|
int[2] d;
|
||||||
|
int e;
|
||||||
|
}
|
||||||
|
|
||||||
|
func void test1()
|
||||||
|
{
|
||||||
|
Foo x;
|
||||||
|
Bar z = cast(x as Baz); // #error: Cannot cast 'Foo' to 'Baz'
|
||||||
|
}
|
||||||
|
func void test2()
|
||||||
|
{
|
||||||
|
Baz x;
|
||||||
|
BazTwo z = cast(x as BazTwo); // #error: Cannot cast 'Baz' to 'BazTwo'
|
||||||
|
}
|
||||||
@@ -1,20 +1,20 @@
|
|||||||
const char AA = ~0;
|
const char AA = ~cast(0 as char);
|
||||||
const char BB = 200 ;
|
const char BB = 200 ;
|
||||||
const uint CC = ~0;
|
const uint CC = ~cast(0 as uint);
|
||||||
const uint DD = FOO;
|
const uint DD = FOO;
|
||||||
|
|
||||||
const FOO = ~0;
|
const FOO = ~cast(0 as uint);
|
||||||
|
|
||||||
uint x = AA;
|
uint x = AA;
|
||||||
uint z = CC;
|
uint z = CC;
|
||||||
char w = FOO;
|
char w = cast(FOO as char);
|
||||||
ushort v = FOO;
|
ushort v = cast(FOO as ushort);
|
||||||
uint z2 = DD;
|
uint z2 = DD;
|
||||||
|
|
||||||
func void test()
|
func void test()
|
||||||
{
|
{
|
||||||
int xx = FOO;
|
int xx = FOO;
|
||||||
int* yy = &&FOO;
|
uint* yy = &&FOO;
|
||||||
}
|
}
|
||||||
|
|
||||||
// #expect: constants.ll
|
// #expect: constants.ll
|
||||||
|
|||||||
10
test/test_suite/distinct/distinct_invalid.c3
Normal file
10
test/test_suite/distinct/distinct_invalid.c3
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
error Error
|
||||||
|
{}
|
||||||
|
|
||||||
|
typedef Error as distinct Foo1; // #error: You cannot create a distinct type from an error
|
||||||
|
|
||||||
|
typedef error as distinct Foo2; // #error: You cannot create a distinct type from an error union
|
||||||
|
|
||||||
|
typedef void as distinct Foo3; // #error: create a distinct type from 'void'
|
||||||
|
|
||||||
|
typedef typeid as distinct Foo4; // #error: create a distinct type from 'typeid'
|
||||||
@@ -3,30 +3,21 @@ module arithmetics;
|
|||||||
func void testAdd(int a, int b)
|
func void testAdd(int a, int b)
|
||||||
{
|
{
|
||||||
a = a + b;
|
a = a + b;
|
||||||
a = a +% b;
|
|
||||||
a +%= b;
|
|
||||||
a += b;
|
a += b;
|
||||||
a += 1;
|
a += 1;
|
||||||
a +%= 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func void testSub(int a, int b)
|
func void testSub(int a, int b)
|
||||||
{
|
{
|
||||||
a = a - b;
|
a = a - b;
|
||||||
a = a -% b;
|
|
||||||
a -%= b;
|
|
||||||
a -= b;
|
a -= b;
|
||||||
a -%= 1;
|
|
||||||
a -= 1;
|
a -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
func void testMult(int a, int b)
|
func void testMult(int a, int b)
|
||||||
{
|
{
|
||||||
a = a * b;
|
a = a * b;
|
||||||
a = a *% b;
|
|
||||||
a *%= b;
|
|
||||||
a *= b;
|
a *= b;
|
||||||
a *%= 1;
|
|
||||||
a *= 1;
|
a *= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,35 +1,3 @@
|
|||||||
func void test1()
|
|
||||||
{
|
|
||||||
double x = 2.3 +% 2; // #error: only valid for integer addition
|
|
||||||
}
|
|
||||||
|
|
||||||
func void test2()
|
|
||||||
{
|
|
||||||
double x = 0;
|
|
||||||
int y = x +% 4; // #error: only valid for integer addition
|
|
||||||
}
|
|
||||||
|
|
||||||
func void test3()
|
|
||||||
{
|
|
||||||
double x = 2.3 -% 2; // #error: only valid for integer subtraction
|
|
||||||
}
|
|
||||||
|
|
||||||
func void test4()
|
|
||||||
{
|
|
||||||
double x = 0;
|
|
||||||
int y = x -% 4; // #error: only valid for integer subtraction
|
|
||||||
}
|
|
||||||
|
|
||||||
func void test5()
|
|
||||||
{
|
|
||||||
double x = 2.3 *% 2; // #error: try * instead
|
|
||||||
}
|
|
||||||
|
|
||||||
func void test6()
|
|
||||||
{
|
|
||||||
double x = 0;
|
|
||||||
int y = x *% 4; // #error: try * instead
|
|
||||||
}
|
|
||||||
|
|
||||||
func void test7()
|
func void test7()
|
||||||
{
|
{
|
||||||
@@ -83,34 +51,34 @@ func void test16()
|
|||||||
uint b = 2;
|
uint b = 2;
|
||||||
ushort c = 3;
|
ushort c = 3;
|
||||||
a = a + c;
|
a = a + c;
|
||||||
int g = a + b; // #error: Cannot add 'int' to 'uint'
|
int g = a + b;
|
||||||
}
|
}
|
||||||
|
|
||||||
func void test17()
|
func void test17()
|
||||||
{
|
{
|
||||||
char a = 100 + 300; // #error: '300' does not fit in type 'char'
|
char a = 100 + 300; // #error: '400' is out of range for 'char'
|
||||||
}
|
}
|
||||||
|
|
||||||
func void test18()
|
func void test18()
|
||||||
{
|
{
|
||||||
char b = 100 + 156; // #error: Cannot fit '256' into type 'char'
|
char b = 100 + 156; // #error: '256' is out of range for 'char'
|
||||||
}
|
}
|
||||||
|
|
||||||
func void test19()
|
func void test19()
|
||||||
{
|
{
|
||||||
ichar b = (-40) - 126; // #error: Cannot fit '-166' into type 'ichar'
|
ichar b = (-40) - 126; // #error: '-166' is out of range for 'ichar'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
func void test20()
|
func void test20()
|
||||||
{
|
{
|
||||||
ichar d = ((-128 - 10) + 10) - 2; // #error: Cannot fit '-130' into type 'ichar'
|
ichar d = ((-128 - 10) + 10) - 2; // #error: '-130' is out of range for 'ichar'
|
||||||
ichar c = 100 * 100; // #error: Cannot fit '10000' into type 'ichar'
|
ichar c = 100 * 100; // #error: '10000' is out of range for 'ichar'
|
||||||
ichar e = (-138 + 30);
|
ichar e = (-138 + 30);
|
||||||
ichar f = -138 + 30; // #error: '-138' does not fit in type 'ichar'
|
ichar f = -138 + 30;
|
||||||
ichar g = -(128);
|
ichar g = -(128);
|
||||||
check(128); // #error: '128' does not fit in type 'ichar'
|
check(128); // #error: '128' is out of range for 'ichar'
|
||||||
}
|
}
|
||||||
|
|
||||||
func void check(ichar x) {}
|
func void check(ichar x) {}
|
||||||
@@ -118,6 +86,6 @@ func void check(ichar x) {}
|
|||||||
|
|
||||||
func char test22()
|
func char test22()
|
||||||
{
|
{
|
||||||
return 300; // #error: '300' does not fit in type 'char'
|
return 300; // #error: '300' is out of range for 'char'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,6 @@ func void test1()
|
|||||||
const int X = 120;
|
const int X = 120;
|
||||||
test2(X); // #error: Cannot implicitly cast 'int' to 'ichar'.
|
test2(X); // #error: Cannot implicitly cast 'int' to 'ichar'.
|
||||||
|
|
||||||
test2(100 + 100); // #error: Cannot fit '200' into type 'ichar'.
|
test2(100 + 100); // #error: '200' is out of range for 'ichar'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,16 +24,16 @@ func void test1(Enum e)
|
|||||||
char b = cast(e as char);
|
char b = cast(e as char);
|
||||||
uint c = cast(e as uint);
|
uint c = cast(e as uint);
|
||||||
float d = cast(e as float);
|
float d = cast(e as float);
|
||||||
uint* f = cast(e as uint*);
|
uint* f = cast(e as uint*); // #error: cast 'Enum' to 'uint*'
|
||||||
}
|
}
|
||||||
|
|
||||||
func void test2(Enum e)
|
func void test2(Enum e)
|
||||||
{
|
{
|
||||||
Struct* g = cast(e as Struct*);
|
Struct* g = cast(e as Struct*); // #error: cast 'Enum' to 'Struct*'
|
||||||
}
|
}
|
||||||
|
|
||||||
func void test3(Enum e)
|
func void test3(Enum e)
|
||||||
{
|
{
|
||||||
//EnumB h = cast(e as EnumB);
|
EnumB h = cast(e as EnumB);
|
||||||
//Func i = cast(e as Func);
|
Func i = cast(e as Func); // #error: cast 'Enum' to 'Func'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ struct Struct
|
|||||||
int x;
|
int x;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Enum : uint
|
enum Enum : uptr
|
||||||
{
|
{
|
||||||
A, B
|
A, B
|
||||||
}
|
}
|
||||||
@@ -18,16 +18,17 @@ typedef func void(int) as FuncSame;
|
|||||||
func void test1(Func arg)
|
func void test1(Func arg)
|
||||||
{
|
{
|
||||||
bool a = cast(arg as bool);
|
bool a = cast(arg as bool);
|
||||||
|
bool b = arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
func void test2(Func arg)
|
func void test2(Func arg)
|
||||||
{
|
{
|
||||||
ichar b = cast(arg as ichar);
|
ichar b = cast(arg as ichar); // #error: Cannot cast 'Func' (func void()) to 'ichar'.
|
||||||
}
|
}
|
||||||
|
|
||||||
func void test3(Func arg)
|
func void test3(Func arg)
|
||||||
{
|
{
|
||||||
uint c = cast(arg as uint);
|
uint c = cast(arg as uint); // #error: Cannot cast 'Func' (func void()) to 'uint'.
|
||||||
}
|
}
|
||||||
|
|
||||||
func void test4(Func arg)
|
func void test4(Func arg)
|
||||||
@@ -40,7 +41,7 @@ func void test7(Func arg)
|
|||||||
usize g = cast(arg as usize);
|
usize g = cast(arg as usize);
|
||||||
FuncOther k = cast(arg as FuncOther);
|
FuncOther k = cast(arg as FuncOther);
|
||||||
FuncSame l = cast(arg as FuncSame);
|
FuncSame l = cast(arg as FuncSame);
|
||||||
FuncOther ke = arg; // #error: Cannot implicitly cast 'Func' (func void()) to 'FuncOther' ('func bool()')
|
FuncOther ke = arg; // #error: Cannot implicitly cast 'Func' (func void()) to 'FuncOther' (func bool())
|
||||||
FuncSame fe = arg;
|
FuncSame fe = arg;
|
||||||
Enum j = cast(arg as Enum); // #error: Cannot cast 'Func' (func void()) to 'Enum'.
|
Enum j = cast(arg as Enum); // #error: Cannot cast 'Func' (func void()) to 'Enum'.
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,10 +25,10 @@ func void test(int* foo)
|
|||||||
store i32* %ptrincdec1, i32** %foo, align 8
|
store i32* %ptrincdec1, i32** %foo, align 8
|
||||||
store i32 10, i32* %y, align 4
|
store i32 10, i32* %y, align 4
|
||||||
%3 = load i32, i32* %y, align 4
|
%3 = load i32, i32* %y, align 4
|
||||||
%add = add nsw i32 %3, 1
|
%add = add i32 %3, 1
|
||||||
store i32 %add, i32* %y, align 4
|
store i32 %add, i32* %y, align 4
|
||||||
%4 = load i32, i32* %y, align 4
|
%4 = load i32, i32* %y, align 4
|
||||||
%sub = sub nsw i32 %4, 1
|
%sub = sub i32 %4, 1
|
||||||
store i32 %sub, i32* %y, align 4
|
store i32 %sub, i32* %y, align 4
|
||||||
store float 2.000000e+00, float* %z, align 4
|
store float 2.000000e+00, float* %z, align 4
|
||||||
%5 = load float, float* %z, align 4
|
%5 = load float, float* %z, align 4
|
||||||
|
|||||||
@@ -9,4 +9,10 @@ func void test1(ichar* cp)
|
|||||||
cp3 += 10;
|
cp3 += 10;
|
||||||
cp3 += a;
|
cp3 += a;
|
||||||
ichar* cp4 = cp - a;
|
ichar* cp4 = cp - a;
|
||||||
|
cp2 - cp3;
|
||||||
|
}
|
||||||
|
func void test2(ichar* cp)
|
||||||
|
{
|
||||||
|
cp + 1;
|
||||||
|
cp * 1.0; // #error: Cannot multiply 'ichar*' by 'compfloat'
|
||||||
}
|
}
|
||||||
@@ -13,6 +13,6 @@ func void test2()
|
|||||||
func void test3()
|
func void test3()
|
||||||
{
|
{
|
||||||
uint myUInt = 1;
|
uint myUInt = 1;
|
||||||
int* p2 = cast(myUInt as int*);
|
int* p2 = cast(myUInt as int*); // #error: Cannot cast 'uint' to 'int*'.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -56,8 +56,8 @@ func void denormalize(InternalFPF* ptr)
|
|||||||
%1 = load i8*, i8** %pp, align 8
|
%1 = load i8*, i8** %pp, align 8
|
||||||
%2 = load i8, i8* %1, align 8
|
%2 = load i8, i8* %1, align 8
|
||||||
%uiuiext = zext i8 %2 to i32
|
%uiuiext = zext i8 %2 to i32
|
||||||
%uadd = add nuw i32 %0, %uiuiext
|
%add = add i32 %0, %uiuiext
|
||||||
store i32 %uadd, i32* %w_cnt, align 4
|
store i32 %add, i32* %w_cnt, align 4
|
||||||
%3 = load i32, i32* %w_cnt, align 4
|
%3 = load i32, i32* %w_cnt, align 4
|
||||||
ret i32 %3
|
ret i32 %3
|
||||||
|
|
||||||
@@ -89,7 +89,7 @@ cond.phi:
|
|||||||
if.then:
|
if.then:
|
||||||
%3 = load i32, i32* %lls, align 4
|
%3 = load i32, i32* %lls, align 4
|
||||||
%4 = load i32, i32* %asa, align 4
|
%4 = load i32, i32* %asa, align 4
|
||||||
%add = add nsw i32 %3, %4
|
%add = add i32 %3, %4
|
||||||
store i32 %add, i32* %asa, align 4
|
store i32 %add, i32* %asa, align 4
|
||||||
br label %if.exit
|
br label %if.exit
|
||||||
|
|
||||||
@@ -97,7 +97,7 @@ if.exit:
|
|||||||
%5 = load i32, i32* %asa, align 4
|
%5 = load i32, i32* %asa, align 4
|
||||||
%6 = load double, double* %val, align 8
|
%6 = load double, double* %val, align 8
|
||||||
%fpui = fptoui double %6 to i32
|
%fpui = fptoui double %6 to i32
|
||||||
%add1 = add nsw i32 %5, %fpui
|
%add1 = add i32 %5, %fpui
|
||||||
ret i32 %add1
|
ret i32 %add1
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ ichar cb = 1;
|
|||||||
ichar cc = 127;
|
ichar cc = 127;
|
||||||
ichar cd = -128;
|
ichar cd = -128;
|
||||||
|
|
||||||
ichar ce = 128; // #error: '128' does not fit
|
ichar ce = 128; // #error: The value '128' is out of range for 'ichar'
|
||||||
ichar cf = -129; // #error: '-129' does not fit
|
ichar cf = -129; // #error: The value '-129' is out of range for 'ichar'
|
||||||
|
|
||||||
ichar cg = 70000; // #error: '70000' does not fit
|
ichar cg = 70000; // #error: The value '70000' is out of range for 'ichar'
|
||||||
ichar ch = -70000; // #error: '-70000' does not fit
|
ichar ch = -70000; // #error: The value '-70000' is out of range for 'ichar'
|
||||||
@@ -48,7 +48,7 @@ while.body:
|
|||||||
if.then:
|
if.then:
|
||||||
%3 = load i32, i32* %a
|
%3 = load i32, i32* %a
|
||||||
%4 = load i32, i32* %argc
|
%4 = load i32, i32* %argc
|
||||||
%add = add nsw i32 %3, %4
|
%add = add i32 %3, %4
|
||||||
call void @test.test2()
|
call void @test.test2()
|
||||||
br label %exit
|
br label %exit
|
||||||
exit:
|
exit:
|
||||||
@@ -77,7 +77,7 @@ while.body6:
|
|||||||
br i1 %eq7, label %if.then8, label %if.exit13
|
br i1 %eq7, label %if.then8, label %if.exit13
|
||||||
if.then8:
|
if.then8:
|
||||||
%7 = load i32, i32* %a
|
%7 = load i32, i32* %a
|
||||||
%add9 = add nsw i32 %7, 2
|
%add9 = add i32 %7, 2
|
||||||
call void @test.test6()
|
call void @test.test6()
|
||||||
br label %exit10
|
br label %exit10
|
||||||
exit10:
|
exit10:
|
||||||
@@ -105,7 +105,7 @@ exit17:
|
|||||||
ret i32 4
|
ret i32 4
|
||||||
while.exit21:
|
while.exit21:
|
||||||
%8 = load i32, i32* %argc
|
%8 = load i32, i32* %argc
|
||||||
%add22 = add nsw i32 0, %8
|
%add22 = add i32 0, %8
|
||||||
call void @test.test5()
|
call void @test.test5()
|
||||||
br label %exit23
|
br label %exit23
|
||||||
exit23:
|
exit23:
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ if.then1:
|
|||||||
if.exit2:
|
if.exit2:
|
||||||
%6 = load i32, i32* %g, align 4
|
%6 = load i32, i32* %g, align 4
|
||||||
%7 = load i32, i32* %z, align 4
|
%7 = load i32, i32* %z, align 4
|
||||||
%add = add nsw i32 %6, %7
|
%add = add i32 %6, %7
|
||||||
store i32 %add, i32* %g, align 4
|
store i32 %add, i32* %g, align 4
|
||||||
br label %foreach.inc
|
br label %foreach.inc
|
||||||
foreach.inc:
|
foreach.inc:
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ foreach.body:
|
|||||||
store i32 %5, i32* %z, align 4
|
store i32 %5, i32* %z, align 4
|
||||||
%6 = load i32, i32* %g, align 4
|
%6 = load i32, i32* %g, align 4
|
||||||
%7 = load i32, i32* %z, align 4
|
%7 = load i32, i32* %z, align 4
|
||||||
%add = add nsw i32 %6, %7
|
%add = add i32 %6, %7
|
||||||
store i32 %add, i32* %g, align 4
|
store i32 %add, i32* %g, align 4
|
||||||
%8 = load { i64, i64 }, { i64, i64 }* %x1, align 8
|
%8 = load { i64, i64 }, { i64, i64 }* %x1, align 8
|
||||||
%9 = extractvalue { i64, i64 } %8, 0
|
%9 = extractvalue { i64, i64 } %8, 0
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ func void test3(int x)
|
|||||||
br i1 %gt, label %if.then, label %if.exit
|
br i1 %gt, label %if.then, label %if.exit
|
||||||
if.then:
|
if.then:
|
||||||
%2 = load i32, i32* %x, align 4
|
%2 = load i32, i32* %x, align 4
|
||||||
%add = add nsw i32 %2, 1
|
%add = add i32 %2, 1
|
||||||
store i32 %add, i32* %x, align 4
|
store i32 %add, i32* %x, align 4
|
||||||
br label %exit
|
br label %exit
|
||||||
exit:
|
exit:
|
||||||
@@ -58,7 +58,7 @@ define void @iftest.test3(i32 %0)
|
|||||||
br i1 %gt, label %if.exit, label %if.else
|
br i1 %gt, label %if.exit, label %if.else
|
||||||
if.else:
|
if.else:
|
||||||
%2 = load i32, i32* %x, align 4
|
%2 = load i32, i32* %x, align 4
|
||||||
%add = add nsw i32 %2, 1
|
%add = add i32 %2, 1
|
||||||
store i32 %add, i32* %x, align 4
|
store i32 %add, i32* %x, align 4
|
||||||
br label %if.exit
|
br label %if.exit
|
||||||
if.exit:
|
if.exit:
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ for.cond:
|
|||||||
|
|
||||||
for.inc8:
|
for.inc8:
|
||||||
%4 = load i32, i32* %i
|
%4 = load i32, i32* %i
|
||||||
%add9 = add nsw i32 %4, 1
|
%add9 = add i32 %4, 1
|
||||||
store i32 %add9, i32* %i
|
store i32 %add9, i32* %i
|
||||||
br label %for.cond
|
br label %for.cond
|
||||||
|
|
||||||
|
|||||||
@@ -98,5 +98,5 @@ entry:
|
|||||||
%sisiext = sext i8 %5 to i32
|
%sisiext = sext i8 %5 to i32
|
||||||
%6 = getelementptr inbounds %struct2.Foo5, %struct2.Foo5* %y, i32 0, i32 0
|
%6 = getelementptr inbounds %struct2.Foo5, %struct2.Foo5* %y, i32 0, i32 0
|
||||||
%7 = load i32, i32* %6, align 16
|
%7 = load i32, i32* %6, align 16
|
||||||
%add = add nsw i32 %sisiext, %7
|
%add = add i32 %sisiext, %7
|
||||||
ret i32 %add
|
ret i32 %add
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ enum Enum : int
|
|||||||
func void test11()
|
func void test11()
|
||||||
{
|
{
|
||||||
int a = Enum.A;
|
int a = Enum.A;
|
||||||
ichar b = Enum.B; // #error: Cannot implicitly convert 'Enum' with underlying type of 'int' to 'ichar'
|
ichar b = Enum.B; // #error: Cannot implicitly cast 'Enum' to 'ichar'
|
||||||
}
|
}
|
||||||
|
|
||||||
func void test12()
|
func void test12()
|
||||||
@@ -100,7 +100,7 @@ func void test13()
|
|||||||
func void test14()
|
func void test14()
|
||||||
{
|
{
|
||||||
char a = 1;
|
char a = 1;
|
||||||
ichar b = a; // #error: cast 'char' to 'ichar'
|
ichar b = a;
|
||||||
}
|
}
|
||||||
|
|
||||||
func void test15()
|
func void test15()
|
||||||
@@ -137,7 +137,7 @@ func void test18()
|
|||||||
func void test19()
|
func void test19()
|
||||||
{
|
{
|
||||||
uint a = 1;
|
uint a = 1;
|
||||||
int b = a; // #error: cast 'uint' to 'int'
|
int b = a;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -150,7 +150,7 @@ func void test1() {
|
|||||||
func void test21()
|
func void test21()
|
||||||
{
|
{
|
||||||
int a = 1;
|
int a = 1;
|
||||||
uint b = a; // #error: cast 'int' to 'uint'
|
uint b = a;
|
||||||
}
|
}
|
||||||
|
|
||||||
func void foo() {}
|
func void foo() {}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ func void enumInferenceTest()
|
|||||||
Inf2 z = C;
|
Inf2 z = C;
|
||||||
if (z == Inf2.A) return;
|
if (z == Inf2.A) return;
|
||||||
if (z == 1) return;
|
if (z == 1) return;
|
||||||
z = 2;
|
z = cast(2 as Inf2);
|
||||||
switch (z)
|
switch (z)
|
||||||
{
|
{
|
||||||
case Inf2.A:
|
case Inf2.A:
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
enum EnumTestOverflow
|
enum EnumTestOverflow
|
||||||
{
|
{
|
||||||
VALUE = 0x80000000, // #error: does not fit in type 'int'
|
VALUE = 0x80000000, // #error: The value '2147483648' is out of range for 'int'
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user