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:
Christoffer Lerno
2021-03-15 16:44:09 +01:00
committed by Christoffer Lerno
parent 8a7f37e4d3
commit 07595df412
52 changed files with 1553 additions and 1462 deletions

View File

@@ -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 }

View File

@@ -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;
} }

View File

@@ -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;

View File

@@ -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:

View File

@@ -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);

View File

@@ -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,

View File

@@ -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:

View File

@@ -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, "-");

View File

@@ -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:

View File

@@ -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:

View File

@@ -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:

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);

View File

@@ -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:

View File

@@ -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 },

View File

@@ -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:

View File

@@ -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

View File

@@ -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

View File

@@ -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.");
} }

View File

@@ -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);

View File

@@ -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;
} }

View File

@@ -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.

View File

@@ -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;

View File

@@ -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[]'
} }

View File

@@ -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'

View File

@@ -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

View 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]);
}

View 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'
}

View File

@@ -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

View 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'

View File

@@ -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;
} }

View File

@@ -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'
} }

View File

@@ -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'
} }

View File

@@ -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'
} }

View File

@@ -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'.
} }

View File

@@ -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

View File

@@ -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'
} }

View File

@@ -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*'.
} }

View File

@@ -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

View File

@@ -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'

View File

@@ -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:

View File

@@ -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:

View File

@@ -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

View File

@@ -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:

View File

@@ -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

View File

@@ -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

View File

@@ -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() {}

View File

@@ -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:

View File

@@ -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'
} }