Changed how structs/unions are parsed so that recovery becomes more robust. Allow for more complex error data. Fixed recursive structs/unions. Corrected prefix precedence rules. Begin work on checking initializer constant-ness. Fixed error on failed arithmetic promotion. Added checks on constant overflow of sub/add/mult. Allow "current_module_name::x" to refer to globals. Added many tests.

This commit is contained in:
Christoffer Lerno
2020-07-23 17:59:42 +02:00
parent f45d6ef84b
commit ed01616f1e
49 changed files with 1289 additions and 314 deletions

View File

@@ -28,8 +28,14 @@ Decl *decl_new(DeclKind decl_kind, TokenId name, Visibility visibility)
decl->decl_kind = decl_kind;
decl->name_token = name;
decl->span = source_span_from_token_id(name);
decl->name = name.index ? TOKSTR(name) : "anon";
decl->member_decl.anonymous = name.index == 0;
if (name.index)
{
decl->name = TOKSTR(name);
}
else
{
decl->name = NULL;
}
decl->visibility = visibility;
return decl;
}
@@ -44,11 +50,12 @@ void decl_set_external_name(Decl *decl)
{
if (decl->visibility == VISIBLE_EXTERN)
{
assert(decl->name);
decl->external_name = decl->name;
return;
}
char buffer[1024];
uint32_t len = sprintf(buffer, "%s.%s", decl->module->name->module, decl->name);
uint32_t len = sprintf(buffer, "%s.%s", decl->module->name->module, decl->name ? decl->name : "anon");
assert(len);
TokenType type = TOKEN_INVALID_TOKEN;
decl->external_name = symtab_add(buffer, len, fnv1a(buffer, len), &type);
@@ -89,11 +96,10 @@ Decl *decl_new_with_type(TokenId name, DeclKind decl_type, Visibility visibility
case DECL_CT_ELSE:
case DECL_CT_ELIF:
case DECL_ATTRIBUTE:
case DECL_MEMBER:
case DECL_LABEL:
UNREACHABLE
}
Type *type = type_new(kind, TOKSTR(name));
Type *type = type_new(kind, !name.index ? "anon" : TOKSTR(name));
type->canonical = type;
type->decl = decl;
decl->type = type;
@@ -110,6 +116,8 @@ const char *decl_var_to_string(VarDeclKind kind)
return "global";
case VARDECL_LOCAL:
return "local";
case VARDECL_MEMBER:
return "member";
case VARDECL_PARAM:
return "param";
case VARDECL_ALIAS:
@@ -133,26 +141,6 @@ Decl *decl_new_var(TokenId name, TypeInfo *type, VarDeclKind kind, Visibility vi
return decl;
}
/**
* Recursively find a node in a declaration.
* @return NULL if it wasn't found, otherwise the member.
*/
Decl *struct_find_name(Decl *decl, const char* name)
{
Decl** compare_members = decl->strukt.members;
VECEACH(compare_members, i)
{
Decl *member = compare_members[i];
if (member->member_decl.anonymous)
{
assert(member->decl_kind == DECL_MEMBER);
Decl *found = struct_find_name(member->member_decl.type_info->type->decl, name);
if (found) return found;
}
else if (member->name == name) return member;
}
return NULL;
}
Expr *expr_new(ExprKind kind, SourceSpan start)
{
@@ -342,10 +330,6 @@ void fprint_type_recursive(Context *context, FILE *file, Type *type, int indent)
case TYPE_ERRTYPE:
DUMPF("(errtype %s)", type->name);
return;
case TYPE_MEMBER:
DUMPF("(member %s", type->name);
DUMPTYPE(type->decl->member_decl.parent->type);
DUMPEND();
case TYPE_TYPEDEF:
DUMPF("(typedef %s", type->name);
DUMPTYPE(type->canonical);
@@ -737,7 +721,7 @@ void fprint_decl_recursive(Context *context, FILE *file, Decl *decl, int indent)
switch (decl->decl_kind)
{
case DECL_VAR:
DUMPF("(var-%s %s", decl_var_to_string(decl->var.kind), decl->name);
DUMPF("(var-%s %s", decl_var_to_string(decl->var.kind), decl->name ? decl->name : "anon");
DUMPTI(decl->var.type_info);
switch (decl->var.kind)
{
@@ -745,6 +729,7 @@ void fprint_decl_recursive(Context *context, FILE *file, Decl *decl, int indent)
case VARDECL_GLOBAL:
case VARDECL_LOCAL:
case VARDECL_PARAM:
case VARDECL_MEMBER:
case VARDECL_LOCAL_CT:
DUMPEXPR(decl->var.init_expr);
break;
@@ -783,11 +768,11 @@ void fprint_decl_recursive(Context *context, FILE *file, Decl *decl, int indent)
if (decl->func.body) DUMPAST(decl->func.body);
DUMPEND();
case DECL_STRUCT:
DUMPF("(struct %s", decl->name);
DUMPF("(struct %s", decl->name ? decl->name : "anon");
DUMPDECLS(decl->strukt.members);
DUMPEND();
case DECL_UNION:
DUMPF("(union %s", decl->name);
DUMPF("(union %s", decl->name ? decl->name : "anon");
DUMPDECLS(decl->strukt.members);
DUMPEND();
case DECL_ENUM:
@@ -863,10 +848,6 @@ void fprint_decl_recursive(Context *context, FILE *file, Decl *decl, int indent)
DUMPF("(import %s", decl->name);
// TODO
DUMPEND();
case DECL_MEMBER:
DUMPF("(member %s", decl->name);
DUMPTI(decl->member_decl.type_info);
DUMPEND();
case DECL_ATTRIBUTE:
DUMPF("(attribute %s)", decl->name);
if (decl->attr.domains & ATTR_FUNC)

View File

@@ -26,6 +26,7 @@ void bigint_read_twos_complement(BigInt *dest, const uint8_t *buf, size_t bit_co
void bigint_add(BigInt *dest, const BigInt *op1, const BigInt *op2);
void bigint_add_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed);
void bigint_sub(BigInt *dest, const BigInt *op1, const BigInt *op2);
void bigint_sub_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed);
void bigint_mul(BigInt *dest, const BigInt *op1, const BigInt *op2);
void bigint_mul_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed);
void bigint_rem(BigInt *dest, const BigInt *op1, const BigInt *op2);

View File

@@ -201,7 +201,6 @@ void compile_files(BuildTarget *target)
compiler_compile(target);
break;
}
TODO
}
@@ -250,6 +249,7 @@ Module *compiler_find_or_create_module(Path *module_name)
void compiler_register_public_symbol(Decl *decl)
{
assert(decl->name);
Decl *prev = stable_get(&compiler.global_symbols, decl->name);
// If the previous symbol was already declared globally, remove it.
stable_set(&compiler.global_symbols, decl->name, prev ? poisoned_decl : decl);

View File

@@ -302,11 +302,6 @@ typedef struct
uint64_t ordinal;
} EnumConstantDecl;
typedef struct
{
Decl *parent;
uint32_t value;
} ErrorConstantDecl;
typedef struct
{
@@ -399,14 +394,6 @@ typedef struct
AstId parent;
} LabelDecl;
typedef struct
{
unsigned index : 32;
bool anonymous : 1;
Decl *parent;
TypeInfo *type_info;
Type *reference_type;
} MemberDecl;
typedef struct _Decl
{
@@ -450,7 +437,6 @@ typedef struct _Decl
EnumDecl enums;
};
};
ErrorConstantDecl error_constant;
ImportDecl import;
VarDecl var;
LabelDecl label;
@@ -464,7 +450,6 @@ typedef struct _Decl
CtIfDecl ct_elif_decl;
Decl** ct_else_decl;
Expr *incr_array_decl;
MemberDecl member_decl;
};
} Decl;
@@ -1062,6 +1047,7 @@ typedef struct _Context
STable scratch_table;
Lexer lexer;
Token tok;
TokenId prev_tok;
Token next_tok;
struct
{
@@ -1142,7 +1128,7 @@ static inline Ast *new_ast(AstKind kind, SourceSpan range)
static inline Ast *extend_ast_with_prev_token(Context *context, Ast *ast)
{
ast->span.end_loc.index = context->tok.id.index - 1;
ast->span.end_loc = context->prev_tok;
return ast;
}
@@ -1332,19 +1318,20 @@ void sema_analysis_pass_conditional_compilation(Context *context);
void sema_analysis_pass_decls(Context *context);
void sema_analysis_pass_functions(Context *context);
bool sema_add_member(Context *context, Decl *decl);
bool sema_add_local(Context *context, Decl *decl);
bool sema_unwrap_var(Context *context, Decl *decl);
bool sema_rewrap_var(Context *context, Decl *decl);
bool sema_analyse_statement(Context *context, Ast *statement);
Decl *sema_resolve_symbol_in_current_dynamic_scope(Context *context, const char *symbol);
Decl *sema_resolve_symbol(Context *context, const char *symbol, Path *path, Decl **ambiguous_other_decl, Decl **private_decl);
bool sema_resolve_type_info(Context *context, TypeInfo *type_info);
bool sema_resolve_type_shallow(Context *context, TypeInfo *type_info);
void sema_error_at_prev_end(Token token, const char *message, ...);
void sema_error_range2(SourceLocation *location, const char *message, ...);
void sema_error_range3(SourceSpan location, const char *message, ...);
void sema_error_range3(SourceSpan span, const char *message, ...);
void sema_verror_range(SourceLocation *location, const char *message, va_list args);
void sema_error(Context *context, const char *message, ...);
@@ -1361,7 +1348,7 @@ static inline SourceSpan source_span_from_token_id(TokenId id)
}
#define RANGE_EXTEND_PREV(x) ((x)->span.end_loc.index = context->tok.id.index - 1)
#define RANGE_EXTEND_PREV(x) ((x)->span.end_loc = context->prev_tok)
void stable_init(STable *table, uint32_t initial_size);
void *stable_set(STable *table, const char *key, void *value);
@@ -1390,6 +1377,7 @@ Type *type_get_vararray(Type *arr_type);
Type *type_get_meta(Type *meta_type);
Type *type_get_indexed_type(Type *type);
Type *type_get_array(Type *arr_type, uint64_t len);
bool type_is_user_defined(Type *type);
Type *type_signed_int_by_bitsize(unsigned bytesize);
Type *type_unsigned_int_by_bitsize(unsigned bytesize);
bool type_is_subtype(Type *type, Type *possible_subtype);
@@ -1423,6 +1411,7 @@ static inline bool type_is_structlike(Type *type)
{
case TYPE_UNION:
case TYPE_STRUCT:
case TYPE_ERRTYPE:
return true;
default:
return false;
@@ -1515,6 +1504,7 @@ static inline Type *type_new(TypeKind kind, const char *name)
Type *type = malloc_arena(sizeof(Type));
memset(type, 0, sizeof(Type));
type->type_kind = kind;
assert(name);
type->name = name;
compiler_add_type(type);
return type;
@@ -1548,9 +1538,6 @@ BinaryOp binaryop_assign_base_op(BinaryOp assign_binary_op);
TokenType binaryop_to_token(BinaryOp type);
Decl *struct_find_name(Decl *decl, const char* name);
static inline const char* struct_union_name_from_token(TokenType type)
{
return type == TOKEN_STRUCT ? "struct" : "union";

View File

@@ -85,6 +85,7 @@ void context_register_external_symbol(Context *context, Decl *decl)
void context_register_global_decl(Context *context, Decl *decl)
{
assert(decl->name);
decl->module = context->module;
switch (decl->decl_kind)
{
@@ -126,7 +127,6 @@ void context_register_global_decl(Context *context, Decl *decl)
case DECL_CT_ELSE:
case DECL_CT_ELIF:
case DECL_ATTRIBUTE:
case DECL_MEMBER:
case DECL_LABEL:
UNREACHABLE
break;

View File

@@ -131,18 +131,25 @@ void sema_verror_range(SourceLocation *location, const char *message, va_list ar
diagnostics.errors++;
}
void sema_error_range2(SourceLocation *location, const char *message, ...)
void sema_prev_at_range3(SourceSpan span, const char *message, ...)
{
va_list list;
va_start(list, message);
sema_verror_range(location, message, list);
va_end(list);
SourceLocation *start = TOKLOC(span.loc);
SourceLocation *end = TOKLOC(span.end_loc);
va_list args;
va_start(args, message);
char buffer[256];
vsnprintf(buffer, 256, message, args);
SourceLocation loc = *start;
loc.length = end->start - start->start + end->length;
print_error2(&loc, buffer, PRINT_TYPE_PREV);
va_end(args);
}
void sema_error_range3(SourceSpan location, const char *message, ...)
void sema_error_range3(SourceSpan span, const char *message, ...)
{
SourceLocation *start = TOKLOC(location.loc);
SourceLocation *end = TOKLOC(location.end_loc);
SourceLocation *start = TOKLOC(span.loc);
SourceLocation *end = TOKLOC(span.end_loc);
SourceLocation loc = *start;
loc.length = end->start - start->start + end->length;
@@ -191,19 +198,6 @@ void sema_error(Context *context, const char *message, ...)
va_end(list);
}
void sema_prev_at_range3(SourceSpan span, const char *message, ...)
{
SourceLocation *start = TOKLOC(span.loc);
SourceLocation *end = TOKLOC(span.end_loc);
va_list args;
va_start(args, message);
char buffer[256];
vsnprintf(buffer, 256, message, args);
SourceLocation loc = *start;
loc.length = end->start - start->start + end->length;
print_error2(&loc, buffer, PRINT_TYPE_PREV);
va_end(args);
}
/*

View File

@@ -136,7 +136,6 @@ typedef enum
DECL_ENUM_CONSTANT,
DECL_TYPEDEF,
DECL_STRUCT,
DECL_MEMBER,
DECL_UNION,
DECL_ENUM,
DECL_ERR,
@@ -468,7 +467,6 @@ typedef enum
TYPE_VARARRAY,
TYPE_SUBARRAY,
TYPE_TYPEID,
TYPE_MEMBER,
TYPE_LAST = TYPE_TYPEID
} TypeKind;
@@ -506,9 +504,10 @@ typedef enum
VARDECL_GLOBAL = 1,
VARDECL_LOCAL = 2,
VARDECL_PARAM = 3,
VARDECL_LOCAL_CT = 4,
VARDECL_LOCAL_CT_TYPE = 5,
VARDECL_ALIAS = 6,
VARDECL_MEMBER = 4,
VARDECL_LOCAL_CT = 5,
VARDECL_LOCAL_CT_TYPE = 6,
VARDECL_ALIAS = 7,
} VarDeclKind;
typedef enum

View File

@@ -240,7 +240,7 @@ void llvm_codegen_setup()
void gencontext_emit_introspection_type(GenContext *context, Decl *decl)
{
llvm_type(decl->type);
LLVMValueRef global_name = LLVMAddGlobal(context->module, llvm_type(type_byte), decl->name);
LLVMValueRef global_name = LLVMAddGlobal(context->module, llvm_type(type_byte), decl->name ? decl->name : "anon");
LLVMSetGlobalConstant(global_name, 1);
LLVMSetInitializer(global_name, LLVMConstInt(llvm_type(type_byte), 1, false));
decl->type->backend_typeid = LLVMBuildPtrToInt(context->builder, global_name, llvm_type(type_typeid), "");
@@ -306,7 +306,6 @@ static void gencontext_emit_decl(GenContext *context, Decl *decl)
case DECL_CT_ELSE:
case DECL_CT_ELIF:
case DECL_ATTRIBUTE:
case DECL_MEMBER:
case DECL_LABEL:
UNREACHABLE
}

View File

@@ -20,7 +20,6 @@ static inline LLVMMetadataRef gencontext_create_debug_type_from_decl(GenContext
case DECL_VAR:
case DECL_ARRAY_VALUE:
case DECL_IMPORT:
case DECL_MEMBER:
case DECL_LABEL:
UNREACHABLE;
case DECL_FUNC:
@@ -95,7 +94,6 @@ LLVMMetadataRef gencontext_get_debug_type(GenContext *context, Type *type)
case TYPE_IXX:
case TYPE_FXX:
case TYPE_TYPEID:
case TYPE_MEMBER:
UNREACHABLE
case TYPE_BOOL:
return gencontext_simple_debug_type(context, type, DW_ATE_boolean);

View File

@@ -121,26 +121,51 @@ static inline LLVMValueRef gencontext_emit_subscript_addr(GenContext *context, E
}
}
static int find_member_index(Decl *parent, Decl *member)
{
VECEACH(parent->strukt.members, i)
{
Decl *maybe_member = parent->strukt.members[i];
if (member == maybe_member)
{
return (int)i;
}
if (!maybe_member->name)
{
if (find_member_index(maybe_member, member) != -1) return (int)i;
}
}
return -1;
}
static LLVMValueRef gencontext_emit_member_addr(GenContext *context, LLVMValueRef value, Decl *parent, Decl *member)
{
assert(member->resolve_status == RESOLVE_DONE);
Decl *current_parent = member->member_decl.parent;
if (current_parent->decl_kind == DECL_MEMBER && current_parent->member_decl.anonymous)
{
value = gencontext_emit_member_addr(context, value, parent, current_parent);
}
switch (current_parent->type->canonical->type_kind)
Decl *found = NULL;
do
{
case TYPE_UNION:
return LLVMBuildBitCast(context->builder, value, LLVMPointerType(llvm_type(member->type), 0), member->name);
case TYPE_ERRTYPE:
return LLVMBuildStructGEP2(context->builder, llvm_type(current_parent->type), value, member->member_decl.index + 1, member->name);
case TYPE_STRUCT:
return LLVMBuildStructGEP2(context->builder, llvm_type(current_parent->type), value, member->member_decl.index, member->name);
default:
UNREACHABLE
}
int index = find_member_index(parent, member);
assert(index > -1);
found = parent->strukt.members[index];
const char *name = found->name ? found->name : "anon";
switch (parent->type->canonical->type_kind)
{
case TYPE_UNION:
value = LLVMBuildBitCast(context->builder, value, LLVMPointerType(llvm_type(found->type), 0), name);
break;
case TYPE_ERRTYPE:
value = LLVMBuildStructGEP2(context->builder, llvm_type(parent->type), value, index + 1, name);
break;
case TYPE_STRUCT:
value = LLVMBuildStructGEP2(context->builder, llvm_type(parent->type), value, index, name);
break;
default:
UNREACHABLE
}
parent = found;
} while (found != member);
return value;
}

View File

@@ -75,7 +75,7 @@ static inline void gencontext_emit_parameter(GenContext *context, Decl *decl, un
assert(decl->decl_kind == DECL_VAR && decl->var.kind == VARDECL_PARAM);
// Allocate room on stack and copy.
decl->ref = gencontext_emit_alloca(context, llvm_type(decl->type), decl->name);
decl->ref = gencontext_emit_alloca(context, llvm_type(decl->type), decl->name ? decl->name : "anon");
gencontext_emit_store(context, decl, LLVMGetParam(context->function, index));
}
@@ -291,7 +291,6 @@ void gencontext_emit_extern_decl(GenContext *context, Decl *decl)
break;
case DECL_ENUM:
TODO
case DECL_MEMBER:
case DECL_ARRAY_VALUE:
case DECL_IMPORT:
case DECL_MACRO:

View File

@@ -22,7 +22,6 @@ static inline LLVMTypeRef llvm_type_from_decl(LLVMContextRef context, Decl *decl
case DECL_VAR:
case DECL_ARRAY_VALUE:
case DECL_IMPORT:
case DECL_MEMBER:
case DECL_LABEL:
UNREACHABLE;
case DECL_FUNC:
@@ -43,11 +42,13 @@ static inline LLVMTypeRef llvm_type_from_decl(LLVMContextRef context, Decl *decl
case DECL_STRUCT:
{
LLVMTypeRef *types = NULL;
LLVMTypeRef type = LLVMStructCreateNamed(context, decl->external_name);
// Avoid recursive issues.
decl->type->backend_type = type;
VECEACH(decl->strukt.members, i)
{
vec_add(types, llvm_get_type(context, decl->strukt.members[i]->type));
}
LLVMTypeRef type = LLVMStructCreateNamed(context, decl->name);
LLVMStructSetBody(type, types, vec_size(types), decl->is_packed);
return type;
}
@@ -55,6 +56,9 @@ static inline LLVMTypeRef llvm_type_from_decl(LLVMContextRef context, Decl *decl
{
Decl *max_type = NULL;
unsigned long long max_size = 0;
LLVMTypeRef type = LLVMStructCreateNamed(context, decl->external_name);
// Avoid recursive issues.
decl->type->backend_type = type;
VECEACH(decl->strukt.members, i)
{
Decl *member = decl->strukt.members[i];
@@ -65,7 +69,6 @@ static inline LLVMTypeRef llvm_type_from_decl(LLVMContextRef context, Decl *decl
max_type = member;
}
}
LLVMTypeRef type = LLVMStructCreateNamed(context, decl->external_name);
if (max_type)
{
LLVMTypeRef type_ref = llvm_get_type(context, max_type->type);
@@ -81,6 +84,9 @@ static inline LLVMTypeRef llvm_type_from_decl(LLVMContextRef context, Decl *decl
return llvm_get_type(context, decl->type);
case DECL_ERR:
{
LLVMTypeRef err_type = LLVMStructCreateNamed(context, decl->external_name);
// Avoid recursive issues.
decl->type->backend_type = err_type;
LLVMTypeRef *types = NULL;
vec_add(types, llvm_get_type(context, type_typeid));
unsigned size = type_size(type_typeid);
@@ -100,9 +106,8 @@ static inline LLVMTypeRef llvm_type_from_decl(LLVMContextRef context, Decl *decl
{
vec_add(types, LLVMIntTypeInContext(context, padding * 8));
}
LLVMTypeRef type = LLVMStructCreateNamed(context, decl->name);
LLVMStructSetBody(type, types, vec_size(types), false);
return type;
LLVMStructSetBody(err_type, types, vec_size(types), false);
return err_type;
}
}
UNREACHABLE
@@ -173,7 +178,6 @@ LLVMTypeRef llvm_get_type(LLVMContextRef context, Type *any_type)
DEBUG_LOG("Generating type %s", any_type->name);
switch (any_type->type_kind)
{
case TYPE_MEMBER:
case TYPE_POISONED:
UNREACHABLE
case TYPE_TYPEID:

View File

@@ -177,9 +177,8 @@ static Expr *parse_unary_expr(Context *context, Expr *left)
Expr *unary = EXPR_NEW_TOKEN(EXPR_UNARY, context->tok);
unary->unary_expr.operator = unaryop_from_token(operator_type);
Precedence rule_precedence = rules[operator_type].precedence;
advance(context);
Expr *right_side = parse_precedence(context, rule_precedence);
Expr *right_side = parse_precedence(context, PREC_UNARY);
CHECK_EXPR(right_side);

View File

@@ -50,6 +50,7 @@ inline void advance(Context *context)
context->lead_comment = context->next_lead_comment;
context->trailing_comment = NULL;
context->next_lead_comment = NULL;
context->prev_tok = context->tok.id;
context->tok = context->next_tok;
while(1)
{
@@ -948,17 +949,6 @@ static inline bool parse_opt_parameter_type_list(Context *context, Visibility pa
#pragma mark --- Parse types
void add_struct_member(Decl *parent, Decl *parent_struct, Decl *member, TypeInfo *type)
{
unsigned index = vec_size(parent_struct->strukt.members);
vec_add(parent_struct->strukt.members, member);
member->member_decl.index = index;
member->member_decl.reference_type = type_new(TYPE_MEMBER, member->name);
member->member_decl.reference_type->canonical = member->member_decl.reference_type;
member->member_decl.reference_type->decl = member;
member->member_decl.type_info = type;
member->member_decl.parent = parent;
}
/**
* Expect pointer to after '{'
@@ -978,16 +968,14 @@ void add_struct_member(Decl *parent, Decl *parent_struct, Decl *member, TypeInfo
* | struct_or_union opt_attributes struct_body
* ;
*
* @param parent the parent if this is the body of member
* @param struct_parent the struct this is the body of
* @param visible_parent the visible struct parent for checking duplicates.
* @param parent the parent of the struct
*/
bool parse_struct_body(Context *context, Decl *parent, Decl *parent_struct, Decl *visible_parent)
bool parse_struct_body(Context *context, Decl *parent)
{
CONSUME_OR(TOKEN_LBRACE, false);
assert(decl_is_struct_type(parent_struct));
assert(decl_is_struct_type(parent));
while (!TOKEN_IS(TOKEN_RBRACE))
{
TokenType token_type = context->tok.type;
@@ -995,56 +983,36 @@ bool parse_struct_body(Context *context, Decl *parent, Decl *parent_struct, Decl
{
DeclKind decl_kind = decl_from_token(token_type);
Decl *member;
const char *name = TOKSTR(context->tok);
Decl *strukt_type = decl_new_with_type(context->tok.id, decl_kind, visible_parent->visibility);
if (context->next_tok.type != TOKEN_IDENT)
{
member = decl_new(DECL_MEMBER, NO_TOKEN_ID, visible_parent->visibility);
member = decl_new_with_type(NO_TOKEN_ID, decl_kind, parent->visibility);
member->span = source_span_from_token_id(context->tok.id);
advance(context);
}
else
{
advance(context);
member = decl_new(DECL_MEMBER, context->tok.id, visible_parent->visibility);
Decl *other = struct_find_name(visible_parent, TOKSTR(context->tok));
if (other)
{
SEMA_TOKEN_ERROR(context->tok, "Duplicate member '%s' found.", TOKSTR(context->tok.id));
SEMA_PREV(other, "Previous declaration with the same name was here.");
decl_poison(visible_parent);
decl_poison(other);
decl_poison(member);
return false;
}
advance_and_verify(context, TOKEN_IDENT);
member = decl_new_with_type(context->tok.id, decl_kind, parent->visibility);
member->span.loc = context->prev_tok;
advance_and_verify(context, TOKEN_IDENT);
}
if (!parse_attributes(context, strukt_type)) return false;
if (!parse_struct_body(context, member, strukt_type, TOKEN_IS(TOKEN_IDENT) ? strukt_type : visible_parent))
if (!parse_attributes(context, member)) return false;
if (!parse_struct_body(context, member))
{
decl_poison(visible_parent);
decl_poison(parent);
return false;
}
VECADD(context->types, strukt_type);
add_struct_member(parent, parent_struct, member, type_info_new_base(strukt_type->type, strukt_type->span));
vec_add(parent->strukt.members, member);
continue;
}
TypeInfo *type = TRY_TYPE_OR(parse_type(context), false);
while (1)
{
EXPECT_OR(TOKEN_IDENT, false);
Decl *member = decl_new(DECL_MEMBER, context->tok.id, visible_parent->visibility);
Decl *other = struct_find_name(visible_parent, member->name);
if (other)
{
SEMA_ERROR(member, "Duplicate member '%s' found.", member->name);
SEMA_PREV(other, "Previous declaration with the same name was here.");
decl_poison(visible_parent);
decl_poison(other);
decl_poison(member);
}
add_struct_member(parent, parent_struct, member, type);
Decl *member = decl_new_var(context->tok.id, type, VARDECL_MEMBER, parent->visibility);
vec_add(parent->strukt.members, member);
advance(context);
if (!TOKEN_IS(TOKEN_COMMA)) break;
if (!try_consume(context, TOKEN_COMMA)) break;
}
CONSUME_OR(TOKEN_EOS, false);
}
@@ -1077,7 +1045,7 @@ static inline Decl *parse_struct_declaration(Context *context, Visibility visibi
return poisoned_decl;
}
if (!parse_struct_body(context, decl, decl, decl))
if (!parse_struct_body(context, decl))
{
return poisoned_decl;
}
@@ -1373,9 +1341,9 @@ static inline Decl *parse_error_declaration(Context *context, Visibility visibil
SEMA_TOKEN_ERROR(context->tok, "Expected an identifier here.");
return poisoned_decl;
}
Decl *member = decl_new(DECL_MEMBER, context->tok.id, visibility);
Decl *member = decl_new_var(context->tok.id, type, VARDECL_MEMBER, visibility);
advance(context);
add_struct_member(err_decl, err_decl, member, type);
vec_add(err_decl->strukt.members, member);
TRY_CONSUME_EOS_OR(poisoned_decl);
}
return err_decl;
@@ -1392,7 +1360,7 @@ static inline Decl *parse_error_declaration(Context *context, Visibility visibil
*/
static inline bool parse_enum_spec(Context *context, TypeInfo **type_ref, Decl*** parameters_ref, Visibility parent_visibility)
{
*type_ref = TRY_TYPE_OR(parse_base_type(context), false);
*type_ref = TRY_TYPE_OR(parse_type(context), false);
if (!try_consume(context, TOKEN_LPAREN)) return true;
while (!try_consume(context, TOKEN_RPAREN))
{

View File

@@ -306,7 +306,7 @@ bool ixxxi(Context *context, Expr *left, Type *canonical, Type *type, CastType c
if (cast_type != CAST_TYPE_EXPLICIT && !bigint_fits_in_bits(&left->const_expr.i, bitsize, is_signed))
{
if (cast_type == CAST_TYPE_OPTIONAL_IMPLICIT) return true;
SEMA_ERROR(left, "'%s' does not fit into '%s'", expr_const_to_error_string(&left->const_expr), canonical->name);
SEMA_ERROR(left, "'%s' does not fit in type '%s'", expr_const_to_error_string(&left->const_expr), canonical->name);
return false;
}
BigInt temp;
@@ -571,7 +571,7 @@ bool enxi(Context *context, Expr* left, Type *from, Type *canonical, Type *type,
if (cast_type != CAST_TYPE_EXPLICIT && type_find_max_type(enum_type_canonical, canonical) != canonical)
{
if (cast_type == CAST_TYPE_OPTIONAL_IMPLICIT) return true;
SEMA_ERROR(left, "Cannot implictly convert '%s' with underlying type of '%s' to '%s',"
SEMA_ERROR(left, "Cannot implicitly convert '%s' with underlying type of '%s' to '%s',"
" use an explicit cast if this is what you want.", type_to_error_string(from),
type_to_error_string(enum_type_canonical), type_to_error_string(canonical));
return false;
@@ -711,7 +711,6 @@ CastKind cast_to_bool_kind(Type *type)
case TYPE_ERRTYPE:
case TYPE_ENUM:
case TYPE_FUNC:
case TYPE_MEMBER:
case TYPE_ARRAY:
case TYPE_VARARRAY:
case TYPE_SUBARRAY:
@@ -751,7 +750,6 @@ bool cast(Context *context, Expr *expr, Type *to_type, CastType cast_type)
case TYPE_POISONED:
case TYPE_VOID:
case TYPE_TYPEID:
case TYPE_MEMBER:
break;
case TYPE_BOOL:
// Bool may convert into integers and floats but only explicitly.

View File

@@ -54,22 +54,43 @@ static inline void sema_set_union_size(Decl *decl)
decl->strukt.size = size;
}
static bool sema_analyse_struct_union(Context *context, Decl *decl);
static inline bool sema_analyse_struct_member(Context *context, Decl *decl)
{
assert(decl->resolve_status == RESOLVE_NOT_DONE);
decl->resolve_status = RESOLVE_RUNNING;
assert(decl->decl_kind == DECL_MEMBER);
if (!sema_resolve_type_info(context, decl->member_decl.type_info)) return decl_poison(decl);
decl->type = decl->member_decl.type_info->type;
decl->resolve_status = RESOLVE_DONE;
return true;
if (decl->name)
{
Decl *other = sema_resolve_symbol_in_current_dynamic_scope(context, decl->name);
if (other)
{
SEMA_ERROR(decl, "Duplicate member name '%s'.", other->name);
SEMA_PREV(other, "Previous declaration was here.");
return false;
}
if (decl->name) sema_add_member(context, decl);
}
switch (decl->decl_kind)
{
case DECL_VAR:
assert(decl->var.kind == VARDECL_MEMBER);
decl->resolve_status = RESOLVE_RUNNING;
if (!sema_resolve_type_info(context, decl->var.type_info)) return decl_poison(decl);
decl->type = decl->var.type_info->type;
decl->resolve_status = RESOLVE_DONE;
return true;
case DECL_STRUCT:
case DECL_UNION:
return sema_analyse_decl(context, decl);
default:
UNREACHABLE
}
}
static inline bool sema_analyse_struct_union(Context *context, Decl *decl)
static bool sema_analyse_struct_union(Context *context, Decl *decl)
{
DEBUG_LOG("Beginning analysis of %s.", decl->name);
DEBUG_LOG("Beginning analysis of %s.", decl->name ? decl->name : "anon");
assert(decl->decl_kind == DECL_STRUCT || decl->decl_kind == DECL_UNION);
if (decl->name) context_push_scope(context);
VECEACH(decl->strukt.members, i)
{
Decl *member = decl->strukt.members[i];
@@ -88,6 +109,7 @@ static inline bool sema_analyse_struct_union(Context *context, Decl *decl)
decl_poison(decl);
}
}
if (decl->name) context_pop_scope(context);
DEBUG_LOG("Analysis complete.");
return decl_ok(decl);
}
@@ -537,6 +559,35 @@ static inline bool sema_analyse_macro(Context *context, Decl *decl)
static inline bool expr_is_constant_eval(Expr *expr)
{
switch (expr->expr_kind)
{
case EXPR_CONST:
return true;
case EXPR_COMPOUND_LITERAL:
return expr_is_constant_eval(expr->expr_compound_literal.initializer);
case EXPR_INITIALIZER_LIST:
{
Expr** init_exprs = expr->expr_initializer.initializer_expr;
switch (expr->expr_initializer.init_type)
{
case INITIALIZER_NORMAL:
{
VECEACH(init_exprs, i)
{
if (!expr_is_constant_eval(init_exprs[i])) return false;
}
return true;
}
default:
return false;
}
}
default:
return false;
}
}
static inline bool sema_analyse_global(Context *context, Decl *decl)
{
@@ -545,8 +596,9 @@ static inline bool sema_analyse_global(Context *context, Decl *decl)
if (decl->var.init_expr)
{
if (!sema_analyse_expr_of_required_type(context, decl->type, decl->var.init_expr, false)) return false;
if (decl->var.init_expr->expr_kind != EXPR_CONST)
if (!expr_is_constant_eval(decl->var.init_expr))
{
SEMA_ERROR(decl->var.init_expr, "The expression must be a constant value.");
return false;
}
@@ -595,6 +647,7 @@ static inline bool sema_analyse_global(Context *context, Decl *decl)
case VARDECL_GLOBAL:
return true;
default:
eprintf("Decl %s %d\n", decl->name, decl->var.kind);
UNREACHABLE
break;
}
@@ -614,22 +667,12 @@ static inline bool sema_analyse_error(Context *context __unused, Decl *decl)
unsigned member_count = vec_size(members);
bool success = true;
unsigned error_size = 0;
context_push_scope(context);
for (unsigned i = 0; i < member_count; i++)
{
Decl *member = members[i];
for (unsigned j = 0; j < i; j++)
{
if (member->name == members[j]->name)
{
SEMA_ERROR(member, "Duplicate error names, please remove one of them.");
SEMA_PREV(members[j], "The previous declaration was here.");
decl_poison(member);
decl_poison(members[j]);
success = false;
break;
}
}
sema_analyse_struct_member(context, member);
success = sema_analyse_struct_member(context, member);
if (!success) continue;
unsigned alignment = type_abi_alignment(member->type);
unsigned size = type_size(member->type);
if (error_size % alignment != 0)
@@ -638,6 +681,8 @@ static inline bool sema_analyse_error(Context *context __unused, Decl *decl)
}
error_size += size;
}
context_pop_scope(context);
if (!success) return false;
sema_set_struct_size(decl);
if (decl->strukt.size > type_size(type_usize))
{
@@ -654,10 +699,10 @@ bool sema_analyse_decl(Context *context, Decl *decl)
{
if (decl->resolve_status == RESOLVE_DONE) return decl_ok(decl);
DEBUG_LOG(">>> Analysing %s.", decl->name);
DEBUG_LOG(">>> Analysing %s.", decl->name ? decl->name : "anon");
if (decl->resolve_status == RESOLVE_RUNNING)
{
SEMA_ERROR(decl, "Recursive dependency on %s.", decl->name);
SEMA_ERROR(decl, "Recursive definition of '%s'.", decl->name ? decl->name : "anon");
decl_poison(decl);
return false;
}
@@ -709,7 +754,6 @@ bool sema_analyse_decl(Context *context, Decl *decl)
case DECL_ARRAY_VALUE:
case DECL_CT_ELSE:
case DECL_CT_ELIF:
case DECL_MEMBER:
case DECL_LABEL:
UNREACHABLE
case DECL_CT_IF:

View File

@@ -311,6 +311,10 @@ static inline bool sema_expr_analyse_identifier(Context *context, Type *to, Expr
{
SEMA_ERROR(expr, "Only macro expansions can be prefixed with '@', please try to remove it.", decl->name);
}
if (decl->resolve_status != RESOLVE_DONE)
{
if (!sema_analyse_decl(context, decl)) return poisoned_decl;
}
if (decl->decl_kind == DECL_VAR && decl->var.failable)
{
expr->failable = true;
@@ -787,13 +791,25 @@ static inline bool sema_expr_analyse_subscript_after_parent_resolution(Context *
return true;
}
static inline bool sema_expr_analyse_subscript(Context *context, Type *to, Expr *expr)
static inline bool sema_expr_analyse_subscript(Context *context, Expr *expr)
{
if (!sema_analyse_expr(context, NULL, expr->subscript_expr.expr)) return false;
expr->failable = expr->subscript_expr.expr->failable;
return sema_expr_analyse_subscript_after_parent_resolution(context, NULL, expr);
}
static inline void insert_access_deref(Expr *expr)
{
Expr *deref = expr_new(EXPR_UNARY, expr->span);
deref->unary_expr.operator = UNARYOP_DEREF;
deref->unary_expr.expr = expr->access_expr.parent;
deref->resolve_status = RESOLVE_DONE;
assert(expr->access_expr.parent->type->canonical->type_kind == TYPE_POINTER);
deref->type = expr->access_expr.parent->type->canonical->pointer;
deref->failable = expr->access_expr.parent->failable;
expr->access_expr.parent = deref;
}
static inline bool sema_expr_analyse_method(Context *context, Expr *expr, Decl *decl, bool is_pointer)
{
const char *name = TOKSTR(expr->access_expr.sub_element);
@@ -802,6 +818,10 @@ static inline bool sema_expr_analyse_method(Context *context, Expr *expr, Decl *
Decl *function = decl->methods[i];
if (function->name == name)
{
if (is_pointer)
{
insert_access_deref(expr);
}
expr->access_expr.ref = function;
expr->type = function->type;
return true;
@@ -810,7 +830,7 @@ static inline bool sema_expr_analyse_method(Context *context, Expr *expr, Decl *
if (decl_is_struct_type(decl))
{
SEMA_ERROR(expr, "There is no element nor method '%s.%s'.", decl->name, name);
SEMA_ERROR(expr, "There is no element or method '%s.%s'.", decl->name, name);
}
else
{
@@ -825,25 +845,22 @@ static Decl *strukt_recursive_search_member(Decl *strukt, const char *name)
VECEACH(strukt->strukt.members, i)
{
Decl *member = strukt->strukt.members[i];
if (member->member_decl.anonymous)
if (member->name == name) return member;
if (decl_is_struct_type(member) && !member->name)
{
Decl *result = strukt_recursive_search_member(member->type->canonical->decl, name);
Decl *result = strukt_recursive_search_member(member, name);
if (result)
{
return result;
}
}
else
{
if (member->name == name) return member;
}
}
return NULL;
}
static inline bool sema_expr_analyse_group(Context *context, Type *to, Expr *expr)
{
if (!sema_analyse_expr(context, to, expr->group_expr)) return false;
if (!sema_analyse_expr(context, NULL, expr->group_expr)) return false;
*expr = *expr->group_expr;
return true;
}
@@ -928,14 +945,14 @@ static bool sema_expr_analyse_type_access(Context *context, Type *to, Expr *expr
if (name == member->name)
{
expr->type_access.decl = member;
expr->type = member->member_decl.reference_type;
expr->type = member->type;
return true;
}
}
SEMA_ERROR(expr, "No function or member '%s.%s' found.", type_to_error_string(type_info->type), name);
return false;
}
/*
static inline bool sema_expr_analyse_member_access(Context *context, Expr *expr)
{
Type *type = expr->access_expr.parent->type->decl->member_decl.type_info->type;
@@ -1012,6 +1029,7 @@ static inline bool sema_expr_analyse_member_access(Context *context, Expr *expr)
sub_element);
return false;
}
*/
static inline bool sema_expr_analyse_access(Context *context, Expr *expr)
@@ -1026,15 +1044,12 @@ static inline bool sema_expr_analyse_access(Context *context, Expr *expr)
Type *parent_type = expr->access_expr.parent->type;
Type *type = parent_type->canonical;
if (type->type_kind == TYPE_MEMBER)
{
return sema_expr_analyse_member_access(context, expr);
}
bool is_pointer = type->type_kind == TYPE_POINTER;
if (is_pointer)
{
type = type->pointer;
}
if (!type_may_have_sub_elements(type))
{
SEMA_ERROR(expr, "Cannot access '%s' on '%s'", TOKSTR(expr->access_expr.sub_element), type_to_error_string(parent_type));
@@ -1060,13 +1075,7 @@ static inline bool sema_expr_analyse_access(Context *context, Expr *expr)
}
if (is_pointer)
{
Expr *deref = expr_new(EXPR_UNARY, expr->span);
deref->unary_expr.operator = UNARYOP_DEREF;
deref->unary_expr.expr = expr->access_expr.parent;
deref->resolve_status = RESOLVE_DONE;
deref->type = type;
deref->failable = expr->access_expr.parent->failable;
expr->access_expr.parent = deref;
insert_access_deref(expr);
}
expr->type = member->type;
expr->access_expr.ref = member;
@@ -1082,7 +1091,7 @@ static DesignatedPath *sema_analyse_init_identifier_string(Context *context, Des
VECEACH(members, i)
{
Decl *member = members[i];
if (member->member_decl.anonymous)
if (!member->name)
{
DesignatedPath temp_path;
temp_path.type = member->type;
@@ -1643,10 +1652,19 @@ static bool sema_expr_analyse_add_sub_assign(Context *context, Expr *expr, Expr
return true;
}
static bool binary_arithmetic_promotion(Context *context, Expr *left, Expr *right, Type *left_type, Type *right_type)
static bool binary_arithmetic_promotion(Context *context, Expr *left, Expr *right, Type *left_type, Type *right_type, Expr *parent, const char *error_message)
{
Type *max = type_find_max_type(left_type, right_type);
return max && type_is_numeric(max) && cast_implicit(context, left, max) && cast_implicit(context, right, max);
if (!max || !type_is_numeric(max))
{
if (!error_message)
{
return sema_type_error_on_binop(context, parent);
}
SEMA_ERROR(parent, error_message, type_to_error_string(left_type), type_to_error_string(right_type));
return false;
}
return cast_implicit(context, left, max) && cast_implicit(context, right, max);
}
/**
@@ -1709,19 +1727,38 @@ static bool sema_expr_analyse_sub(Context *context, Type *to, Expr *expr, Expr *
}
// 7. Attempt arithmetic promotion, to promote both to a common type.
if (!binary_arithmetic_promotion(context, left, right, left_type, right_type))
if (!binary_arithmetic_promotion(context, left, right, left_type, right_type, expr, "Cannot subtract '%s' from '%s'"))
{
SEMA_ERROR(expr, "Cannot subtract '%s' from '%s'", type_to_error_string(left_type), type_to_error_string(right_type));
return false;
}
left_type = left->type->canonical;
// 8. Handle constant folding.
if (both_const(left, right))
{
switch (left->const_expr.kind)
expr->expr_kind = EXPR_CONST;
expr->const_expr.kind = left_type->type_kind;
switch (left_type->type_kind)
{
case ALL_INTS:
bigint_sub(&expr->const_expr.i, &left->const_expr.i, &right->const_expr.i);
if (is_mod && left_type != type_compint)
{
bigint_sub_wrap(&expr->const_expr.i,
&left->const_expr.i,
&right->const_expr.i,
left_type->builtin.bitsize,
type_is_signed(left_type));
}
else
{
bigint_sub(&expr->const_expr.i, &left->const_expr.i, &right->const_expr.i);
}
if (expr_const_int_overflowed(&expr->const_expr))
{
SEMA_ERROR(expr, "Cannot fit '%s' into type '%s'.", expr_const_to_error_string(&expr->const_expr), type_to_error_string(left_type));
return false;
}
break;
case ALL_FLOATS:
// IMPROVE precision.
@@ -1730,8 +1767,6 @@ static bool sema_expr_analyse_sub(Context *context, Type *to, Expr *expr, Expr *
default:
UNREACHABLE
}
expr->expr_kind = EXPR_CONST;
expr->const_expr.kind = left->const_expr.kind;
}
// 9. Is this -%? That's not ok unless we are adding integers.
@@ -1807,19 +1842,34 @@ static bool sema_expr_analyse_add(Context *context, Type *to, Expr *expr, Expr *
// 5. Do the binary arithmetic promotion (finding a common super type)
// If none can be find, send an error.
if (!binary_arithmetic_promotion(context, left, right, left_type, right_type))
if (!binary_arithmetic_promotion(context, left, right, left_type, right_type, expr, "Cannot add '%s' to '%s'"))
{
SEMA_ERROR(expr, "Cannot add '%s' to '%s'", type_to_error_string(left_type), type_to_error_string(right_type));
return false;
}
left_type = left->type->canonical;
// 6. Handle the "both const" case. We should only see ints and floats at this point.
if (both_const(left, right))
{
expr->expr_kind = EXPR_CONST;
expr->const_expr.kind = left_type->type_kind;
switch (left->const_expr.kind)
{
case ALL_INTS:
bigint_add(&expr->const_expr.i, &left->const_expr.i, &right->const_expr.i);
if (is_mod && left_type != type_compint)
{
bigint_add_wrap(&expr->const_expr.i, &left->const_expr.i, &right->const_expr.i, left_type->builtin.bitsize, type_is_signed(left_type));
}
else
{
bigint_add(&expr->const_expr.i, &left->const_expr.i, &right->const_expr.i);
}
if (expr_const_int_overflowed(&expr->const_expr))
{
SEMA_ERROR(expr, "Cannot fit '%s' into type '%s'.", expr_const_to_error_string(&expr->const_expr), type_to_error_string(left_type));
return false;
}
break;
case ALL_FLOATS:
expr->const_expr.f = left->const_expr.f + right->const_expr.f;
@@ -1827,8 +1877,6 @@ static bool sema_expr_analyse_add(Context *context, Type *to, Expr *expr, Expr *
default:
UNREACHABLE
}
expr->expr_kind = EXPR_CONST;
expr->const_expr.kind = left->const_expr.kind;
}
// 7. Is this +%? That's not ok unless we are adding integers.
@@ -1865,9 +1913,8 @@ static bool sema_expr_analyse_mult(Context *context, Type *to, Expr *expr, Expr
Type *right_type = right->type->canonical;
// 2. Perform promotion to a common type.
if (!binary_arithmetic_promotion(context, left, right, left_type, right_type))
if (!binary_arithmetic_promotion(context, left, right, left_type, right_type, expr, "Cannot multiply '%s' by '%s'"))
{
SEMA_ERROR(expr, "Cannot multiply '%s' with '%s'", type_to_error_string(left->type), type_to_error_string(right->type));
return false;
}
@@ -1880,7 +1927,7 @@ static bool sema_expr_analyse_mult(Context *context, Type *to, Expr *expr, Expr
// 4. Prevent *% use on non-integers.
if (is_mod && !type_is_any_integer(left_type))
{
SEMA_ERROR(expr, "*% can only be used with integer types, try * instead.");
SEMA_ERROR(expr, "*%% can only be used with integer types, try * instead.");
return false;
}
@@ -1888,7 +1935,7 @@ static bool sema_expr_analyse_mult(Context *context, Type *to, Expr *expr, Expr
if (both_const(left, right))
{
expr->expr_kind = EXPR_CONST;
expr->const_expr.kind = left->const_expr.kind;
expr->const_expr.kind = left_type->type_kind;
switch (left->const_expr.kind)
{
@@ -1899,11 +1946,18 @@ static bool sema_expr_analyse_mult(Context *context, Type *to, Expr *expr, Expr
bigint_mul_wrap(&expr->const_expr.i,
&left->const_expr.i,
&right->const_expr.i,
is_mod,
left_type->builtin.bitsize);
return true;
left_type->builtin.bitsize,
type_is_signed(left_type));
}
else
{
bigint_mul(&expr->const_expr.i, &left->const_expr.i, &right->const_expr.i);
}
if (expr_const_int_overflowed(&expr->const_expr))
{
SEMA_ERROR(expr, "Cannot fit '%s' into type '%s'.", expr_const_to_error_string(&expr->const_expr), type_to_error_string(left_type));
return false;
}
bigint_mul(&expr->const_expr.i, &left->const_expr.i, &right->const_expr.i);
break;
case ALL_FLOATS:
expr->const_expr.f = left->const_expr.f * right->const_expr.f;
@@ -1930,9 +1984,8 @@ static bool sema_expr_analyse_div(Context *context, Type *to, Expr *expr, Expr *
Type *right_type = right->type->canonical;
// 2. Perform promotion to a common type.
if (!binary_arithmetic_promotion(context, left, right, left_type, right_type))
if (!binary_arithmetic_promotion(context, left, right, left_type, right_type, expr, "Cannot divide '%s' by '%s'."))
{
SEMA_ERROR(expr, "Cannot divide '%s' by '%s'.", type_to_error_string(left_type), type_to_error_string(right_type));
return false;
}
@@ -2038,9 +2091,9 @@ static bool sema_expr_analyse_bit(Context *context, Type *to, Expr *expr, Expr *
Type *left_type = left->type->canonical;
Type *right_type = right->type->canonical;
if (!binary_arithmetic_promotion(context, left, right, left_type, right_type))
if (!binary_arithmetic_promotion(context, left, right, left_type, right_type, expr, NULL))
{
return sema_type_error_on_binop(context, expr);
return false;
}
// 4. Do constant folding if both sides are constant.
@@ -2309,7 +2362,6 @@ static bool sema_expr_analyse_comp(Context *context, Expr *expr, Expr *left, Exp
case TYPE_VARARRAY:
case TYPE_SUBARRAY:
case TYPE_TYPEID:
case TYPE_MEMBER:
// Only != and == allowed.
goto ERR;
case ALL_INTS:
@@ -2551,7 +2603,6 @@ static bool sema_expr_analyse_not(Context *context, Type *to, Expr *expr, Expr *
case TYPE_ENUM:
case TYPE_ERRTYPE:
case TYPE_TYPEID:
case TYPE_MEMBER:
SEMA_ERROR(expr, "Cannot use 'not' on %s", type_to_error_string(inner->type));
return false;
}
@@ -3283,7 +3334,7 @@ static inline bool sema_analyse_expr_dispatch(Context *context, Type *to, Expr *
case EXPR_CALL:
return sema_expr_analyse_call(context, to, expr);
case EXPR_SUBSCRIPT:
return sema_expr_analyse_subscript(context, to, expr);
return sema_expr_analyse_subscript(context, expr);
case EXPR_GROUP:
return sema_expr_analyse_group(context, to, expr);
case EXPR_ACCESS:
@@ -3317,15 +3368,16 @@ bool sema_analyse_expr(Context *context, Type *to, Expr *expr)
{
case RESOLVE_NOT_DONE:
expr->resolve_status = RESOLVE_RUNNING;
if (!sema_analyse_expr_dispatch(context, to, expr)) return expr_poison(expr);
expr->resolve_status = RESOLVE_DONE;
break;
case RESOLVE_RUNNING:
SEMA_ERROR(expr, "Recursive resolution of expression");
return expr_poison(expr);
case RESOLVE_DONE:
return expr_ok(expr);
if (!expr_ok(expr)) return false;
break;
}
if (!sema_analyse_expr_dispatch(context, to, expr)) return expr_poison(expr);
expr->resolve_status = RESOLVE_DONE;
if (expr->expr_kind == EXPR_IDENTIFIER)
{
if (expr->identifier_expr.decl->decl_kind == DECL_FUNC)

View File

@@ -11,6 +11,10 @@ int sema_check_comp_time_bool(Context *context, Expr *expr);
bool sema_analyse_function_body(Context *context, Decl *func);
void context_pop_scope(Context *context);
void context_push_scope_with_flags(Context *context, ScopeFlags flags);
static inline void context_push_scope(Context *context)
{
context_push_scope_with_flags(context, SCOPE_NONE);
}
#define PUSH_X(ast, X) AstId _old_##X##_defer = context->X##_defer; AstId _old_##X = context->X##_target; context->X##_target = astid(ast); context->X##_defer = context->current_scope->defers.start
#define POP_X(X) context->X##_target = _old_##X; context->X##_defer = _old_##X##_defer
#define PUSH_CONTINUE(ast) PUSH_X(ast, continue)

View File

@@ -33,6 +33,10 @@ static Decl *sema_resolve_path_symbol(Context *context, const char *symbol, Path
*ambiguous_other_decl = NULL;
Decl *decl = NULL;
bool path_found = false;
if (matches_subpath(context->module->name, path))
{
return stable_get(&context->module->symbols, symbol);
}
VECEACH(context->imports, i)
{
Decl *import = context->imports[i];
@@ -64,6 +68,21 @@ static Decl *sema_resolve_path_symbol(Context *context, const char *symbol, Path
return decl;
}
Decl *sema_resolve_symbol_in_current_dynamic_scope(Context *context, const char *symbol)
{
if (context->current_scope)
{
Decl **first = context->current_scope->local_decl_start;
Decl **current = context->last_local - 1;
while (current >= first)
{
if (current[0]->name == symbol) return current[0];
current--;
}
}
return NULL;
}
Decl *sema_resolve_symbol(Context *context, const char *symbol, Path *path, Decl **ambiguous_other_decl,
Decl **private_decl)
{
@@ -121,19 +140,20 @@ Decl *sema_resolve_symbol(Context *context, const char *symbol, Path *path, Decl
static inline bool sema_append_local(Context *context, Decl *decl)
{
Decl *** vars = &context->active_function_for_analysis->func.annotations->vars;
unsigned num_vars = vec_size(*vars);
if (num_vars == MAX_LOCALS - 1 || context->last_local == &context->locals[MAX_LOCALS - 1])
if (context->last_local == &context->locals[MAX_LOCALS - 1])
{
SEMA_ERROR(decl, "Reached the maximum number of locals.");
return false;
}
*vars = VECADD(*vars, decl);
context->last_local[0] = decl;
context->last_local++;
return true;
}
bool sema_add_member(Context *context, Decl *decl)
{
return sema_append_local(context, decl);
}
bool sema_add_local(Context *context, Decl *decl)
{
Decl *dummy;
@@ -146,6 +166,15 @@ bool sema_add_local(Context *context, Decl *decl)
decl_poison(other);
return false;
}
Decl ***vars = &context->active_function_for_analysis->func.annotations->vars;
unsigned num_vars = vec_size(*vars);
if (num_vars == MAX_LOCALS - 1)
{
SEMA_ERROR(decl, "Reached the maximum number of locals.");
return false;
}
vec_add(*vars, decl);
decl->resolve_status = RESOLVE_DONE;
return sema_append_local(context, decl);
}
@@ -155,6 +184,7 @@ bool sema_unwrap_var(Context *context, Decl *decl)
alias->var.kind = VARDECL_ALIAS;
alias->var.alias = decl;
alias->var.failable = false;
decl->resolve_status = RESOLVE_DONE;
return sema_append_local(context, decl);
}

View File

@@ -102,6 +102,9 @@ static inline bool analyse_func_body(Context *context, Decl *decl)
void sema_analysis_pass_decls(Context *context)
{
DEBUG_LOG("Pass: Decl analysis %s", context->file->name);
context->current_scope = &context->scopes[0];
context->current_scope->scope_id = 0;
context->last_local = &context->locals[0];
VECEACH(context->enums, i)
{
sema_analyse_decl(context, context->enums[i]);

View File

@@ -55,10 +55,6 @@ void context_push_scope_with_label(Context *context, Decl *label)
}
}
static inline void context_push_scope(Context *context)
{
context_push_scope_with_flags(context, SCOPE_NONE);
}
static inline void context_pop_defers(Context *context)
{

View File

@@ -104,10 +104,6 @@ static bool sema_resolve_type_identifier(Context *context, TypeInfo *type_info)
case DECL_ERR:
case DECL_ENUM:
case DECL_TYPEDEF:
if (decl->resolve_status == RESOLVE_NOT_DONE)
{
if (!sema_analyse_decl(context, decl)) return decl_poison(decl);
}
type_info->type = decl->type;
type_info->resolve_status = RESOLVE_DONE;
DEBUG_LOG("Resolved %s.", TOKSTR(type_info->unresolved.name_loc));
@@ -128,7 +124,6 @@ static bool sema_resolve_type_identifier(Context *context, TypeInfo *type_info)
case DECL_CT_IF:
case DECL_CT_ELIF:
case DECL_ATTRIBUTE:
case DECL_MEMBER:
UNREACHABLE
}
UNREACHABLE

View File

@@ -6,12 +6,16 @@
void sema_shadow_error(Decl *decl, Decl *old)
{
SEMA_ERROR(decl, "The '%s' would shadow a previous declaration.", decl->name);
SEMA_ERROR(decl, "'%s' would shadow a previous declaration.", decl->name);
SEMA_PREV(old, "The previous use of '%s' was here.", decl->name);
}
bool sema_resolve_type_info(Context *context, TypeInfo *type_info)
{
if (!sema_resolve_type_shallow(context, type_info)) return false;
return true;
Type *type = type_info->type;
// usize and similar typedefs will not have a decl.
if (type->type_kind == TYPE_TYPEDEF && type->decl == NULL) return true;
if (!type_is_user_defined(type)) return true;
return sema_analyse_decl(context, type->decl);
}

View File

@@ -122,8 +122,6 @@ const char *type_to_error_string(Type *type)
}
asprintf(&buffer, "%s*", type_to_error_string(type->pointer));
return buffer;
case TYPE_MEMBER:
return "member";
case TYPE_STRING:
return "string";
case TYPE_ARRAY:
@@ -191,8 +189,6 @@ size_t type_size(Type *type)
case ALL_FLOATS:
case TYPE_ERR_UNION:
return type->builtin.bytesize;
case TYPE_MEMBER:
return type_size(type->decl->var.type_info->type);
case TYPE_FUNC:
case TYPE_POINTER:
case TYPE_VARARRAY:
@@ -228,8 +224,6 @@ unsigned int type_abi_alignment(Type *type)
case ALL_FLOATS:
case TYPE_ERR_UNION:
return type->builtin.abi_alignment;
case TYPE_MEMBER:
return type_abi_alignment(type->decl->var.type_info->type);
case TYPE_FUNC:
case TYPE_POINTER:
case TYPE_VARARRAY:
@@ -347,6 +341,22 @@ Type *type_get_vararray(Type *arr_type)
return type_generate_subarray(arr_type, false);
}
bool type_is_user_defined(Type *type)
{
switch (type->type_kind)
{
case TYPE_ENUM:
case TYPE_FUNC:
case TYPE_STRUCT:
case TYPE_UNION:
case TYPE_ERRTYPE:
case TYPE_TYPEDEF:
return true;
default:
return false;
}
}
Type *type_get_indexed_type(Type *type)
{
switch (type->type_kind)
@@ -696,7 +706,6 @@ Type *type_find_max_type(Type *type, Type *other)
case TYPE_ERRTYPE:
if (other->type_kind == TYPE_ERRTYPE) return type_error;
return NULL;
case TYPE_MEMBER:
case TYPE_FUNC:
case TYPE_UNION:
case TYPE_ERR_UNION:

View File

@@ -68,11 +68,11 @@ class Issues:
print('"' + parts[3] + '"')
if len(self.errors) > 0:
self.set_failed()
print("Expected errors that never occured:")
print("Expected errors that never occurred:")
num = 1
for key, value in self.errors.items():
pos = key.split(":", 2)
print(str(num) + ". " + pos[0] + " line: " + pos[1] + " expected: " + value)
print(str(num) + ". " + pos[0] + " line: " + pos[1] + " expected: \"" + value + "\"")
num += 1
def compile(self, args):
@@ -80,7 +80,7 @@ class Issues:
code = subprocess.run(path + 'c3c ' + args, universal_newlines=True, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
if code.returncode != 0 and code.returncode != 1:
self.set_failed()
print("Error: " + code.stderr)
print("Error (" + str(code.returncode) + "): " + code.stderr)
self.has_errors = True
return
self.parse_result(code.stderr.splitlines(keepends=False))

View File

@@ -10,4 +10,5 @@ module comments;
func void test()
{
return;
}
}

View File

@@ -1,11 +0,0 @@
enum EnumTestOverflow
{
VALUE = 0x80000000, // #error: does not fit into 'int'
}
enum EnumTestErrorType : float // #error: must be an integer type not 'float'
{
VALUE_BOOM
}

View File

@@ -1,19 +0,0 @@
enum EnumWithErrorWithMissingName : int (int) // #error: function parameter must be named
{
TEST
}
enum EnumWithErrorData : int (int // #error: end of the parameter list
{
TEST
}
error TheError
{
union // #error: A type name was expected here
{
int a;
int b;
}
}

View File

@@ -1,9 +1,12 @@
module foo;
error TooBig // #error: Error type may not exceed pointer
error TheError
{
usize a;
char b;
}
union // #error: A type name was expected here
{
int a;
int b;
}
}

View File

@@ -5,5 +5,16 @@ error TheError
int a;
}
error TheError2
{
byte a;
byte b;
}
error TheError3
{
void *a;
}
error OtherError;

View File

@@ -0,0 +1,5 @@
error TooBig // #error: Error type may not exceed pointer
{
usize a;
char b;
}

View File

@@ -35,4 +35,15 @@ func void testDiv(int a, int b)
a = a / b;
a /= b;
a /= 1;
}
func void testAssignment()
{
char x = -3 - 5;
char c = -128;
}
func byte test22()
{
return 100;
}

View File

@@ -0,0 +1,129 @@
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()
{
double x = 1.2 / 0; // #error: division by zero is not allowed
}
func void test8()
{
int y = 0 / 0; // #error: division by zero is not allowed
}
func void test9()
{
int y = 0;
int x = y / 0; // #error: division by zero is not allowed
}
func void test10()
{
10 = 20; // #error: Expression is not assignable
}
func void test11()
{
'10' = '20'; // #error: Expression is not assignable
}
func void test12()
{
true = false; // #error: Expression is not assignable
}
func void test13()
{
"a" = "b"; // #error: Expression is not assignable
}
func void test14()
{
1.2 = 1.3; // #error: Expression is not assignable
}
func void test15()
{
nil = nil; // #error: Expression is not assignable
}
func void test16()
{
int a = 0;
uint b = 2;
ushort c = 3;
a = a + c;
int c = a + b; // #error: Cannot add 'int' to 'uint'
}
func void test17()
{
byte a = 100 + 300; // #error: '300' does not fit in type 'byte'
}
func void test18()
{
byte b = 100 + 156; // #error: Cannot fit '256' into type 'byte'
}
func void test19()
{
char b = (-40) - 126; // #error: Cannot fit '-166' into type 'char'
}
func void test20()
{
char d = ((-128 - 10) + 10) - 2; // #error: Cannot fit '-130' into type 'char'
char c = 100 * 100; // #error: Cannot fit '10000' into type 'char'
char e = (-138 + 30);
char f = -138 + 30; // #error: '-138' does not fit in type 'char'
char g = -(128);
check(128); // #error: '128' does not fit in type 'char'
}
func void check(char x) {}
func void test21()
{
int a = 0;
int b = 2;
a++ = b++; // #error: Expression is not assignable
}
func byte test22()
{
return 300; // #error: '300' does not fit in type 'byte'
}

View File

@@ -0,0 +1,5 @@
func void test1()
{
int* p;
*p = 10;
}

View File

@@ -0,0 +1,33 @@
// #skip
// TODO string str = "hello";
char* str2 = "hello";
char[] str3 = "hello";
func void test2()
{
int[2] a = { 1, 2 };
int[2] b = 30; // #error: Cannot implicitly cast 'compint' to 'int[2]'
int[2] c = a;
}
int[2] a1 = { 1, 2 };
int[2] a2 = 30; // #error: Cannot implicitly cast 'compint' to 'int[2]'
int[2] a3 = a1;
// i8[] a; // @error{definition of variable with array type needs an explicit size or an initializer}
char ca = 0;
char cb = 1;
char cc = 127;
char cd = -128;
char ce = 128; // #error: '128' does not fit
char cf = -129; // #error: '-129' does not fit
char cg = 70000; // #error: '70000' does not fit
char ch = -70000; // #error: '-70000' does not fit

View File

@@ -0,0 +1,73 @@
// #skip
i32[+] a;
a += 10;
public func i32 main() {
a += 20; // @error{cannot add values to incremental array in function scope}
return 0;
}
const i32[+] A;
A += 10;
A += 20;
A += 30;
i32[+] b;
func void test1() {
i32[+] d; // @error{incremental arrays not allowed in function scope}
}
i32[+] c;
func void test2()
{
b += 10; // @error{cannot add values to incremental array in function scope}
}
i32[+] a = {} // @error{incremental array cannot have initializer}
i32 g;
i8[2] h = { 1, 2 }
g += 10; // @error{'a' is not an incremental array}
xyz += 20; // @error{module test has no symbol b}
h += 30; // @error{'d' is not an incremental array}
test2 += 20; // @error{'main' is not an incremental array}
i32[+] i;
i += xyz; // @error{use of undeclared identifier c}
a += test2; // @error{invalid type conversion from 'i32 ()' to 'i32'}
i32[+] k;
k += 1;
k += 2;
k += 3;
public func void test3()
{
i32 c = a; // @error{invalid type conversion from 'i32[3]' to 'i32'}
}
struct Point
{
int x;
int y;
}
Point[+] points;
points += { 10, 11 }
points += { 20, main } // @error{invalid type conversion from 'i32 ()' to 'i32'}
points += { 30, 31 }

View File

@@ -0,0 +1,17 @@
// #skip
type State enum u8 {
A,
B,
}
State += 10; // @error{expected identifier after incremental enum}
type State enum u8 {
A,
B,
}
State += C;
State += D;

View File

@@ -0,0 +1,31 @@
/*
public func int main()
{
for (;;) {}
return 0;
}
public func int test1()
{
for (int x = 0;;)
{
}
return 0;
}
public func int test2()
{
for (int x = 0; 1 ;)
{
}
return 0;
}
public func int test3()
{
for (; 1 ;2)
{
}
return 0;
}
*/

View File

@@ -0,0 +1,7 @@
func void foo() {}
public func int main()
{
for (; foo() ; ) {} // #error: Cannot implicitly cast 'void' to 'bool'
return 0;
}

View File

@@ -0,0 +1,24 @@
public func int main()
{
do FOO:
{
while FOO: (1) // #error: would shadow a previous declaration
{
return 1;
}
}
return 0;
}
func void test1()
{
do FOO:
{
while (1)
{
break BAR; // #error: Cannot find a labelled statement with the name 'BAR'
}
}
}

View File

@@ -0,0 +1,136 @@
enum Foo
{
A, B
}
enum Bar
{
B
}
func void test_other_enum()
{
Foo f = A;
switch (f)
{
case Foo.A:
break;
case B:
break;
case Bar.B: // #error: Cannot implicitly cast 'Bar' to 'Foo'
break;
}
}
func void test_check_nums()
{
Foo f = A;
switch (f)
{
case 2:
break;
case 0:
break;
}
}
func void test_scope(int i)
{
switch (i)
{
case 1:
int a = 0;
break;
case 2:
test_scope(a + 1); // #error: Identifier 'a' could not be found
}
}
func void test_duplicate_case(int i)
{
switch (i)
{
case 1:
break;
case 2:
break;
case 1: // #error: same case value appears
break;
}
}
func void test_duplicate_case2(Foo i)
{
switch (i)
{
case A:
break;
case 2:
break;
case A: // #error: same case value appears
break;
}
}
func void test_duplicate_case3(Foo i)
{
switch (i)
{
case A:
break;
case 0: // #error: same case value appears
break;
}
}
enum Baz
{
A, B, C, D
}
func void test_missing_all_cases(Baz x)
{
switch (x) // -error: 4 enumeration values not handled in switch: A, B, C, ...
{
}
}
func void test_missing_some_cases(Baz x)
{
switch (x) // -error: 4 enumeration B, C and D not handled in switch
{
case A:
break;
}
}
func void test_missing_some_cases2(Baz x)
{
switch (x) // -error: 4 enumeration B and D not handled in switch
{
case C:
case A:
break;
}
}
func void test_missing_some_cases3(Baz x)
{
switch (x) // -error: 4 enumeration B and D not handled in switch
{
case B:
case C:
case A:
break;
}
}
func void test_missing_no_cases(Baz x)
{
switch (x)
{
default:
break;
}
}

View File

@@ -0,0 +1,70 @@
// @warnings{no-unused}
module test;
struct Aa
{
int a;
int a; // #error: Duplicate member name 'a'
}
struct Bb
{
int a;
struct a // #error: Duplicate member name 'a'
{
int b;
}
}
union Cc
{
int a;
int a; // #error: Duplicate member name 'a'
struct b
{
int c;
int c; // #error: Duplicate member name 'c'
}
}
struct Dd
{
int b;
int a;
struct
{
union
{
short a; // #error: Duplicate member name 'a'
int b; // #error: Duplicate member name 'b'
}
}
}
union Ee
{
int a;
struct
{
short a; // #error: Duplicate member name 'a'
}
}
struct Ff
{
struct
{
int a;
}
struct b
{
int a;
}
union
{
int a; // #error: Duplicate member name 'a'
}
}

View File

@@ -0,0 +1,84 @@
module test;
struct Multi
{
int a, b, c;
}
struct Point
{
int a;
struct bb
{
int b;
}
struct
{
int b;
int c;
struct
{
Point* p;
}
}
union
{
int d;
short e;
}
union uu {
int d;
ushort e;
}
}
func void tester()
{
Multi m;
m.a = 1;
Point p;
p.a = 1;
p.bb.b = 2;
p.b = 3;
p.c = 4;
p.p = nil;
p.d = 5;
p.e = 6;
p.uu.d = 7;
p.uu.e = 8;
Point *p2 = &p;
p2.bb.b = 3;
p = { a = 1, bb.b = 3, e = 2 };
}
struct Aa1
{
struct bb
{
int b;
}
struct
{
int c;
}
}
func void test_conversion_struct()
{
Aa1 a1;
int aa = a1.bb; // #error: Cannot implicitly cast 'bb' to 'int'
}
struct Struct
{
int a;
}
func void myfunc()
{
Struct s;
s.b = 10; // #error: There is no element or method 'Struct.b'
}

View File

@@ -0,0 +1,184 @@
module test;
func void test1()
{
char a = 1;
int b = 2;
char c = b > a ? 1 : 0;
}
func void test2()
{
char a = 1;
char b = 2;
char c = a + b;
}
func void test3()
{
char a = 1;
int b = 2;
char c = a + b; // #error: Cannot implicitly cast 'int' to 'char'
}
func void test4()
{
char a = 1;
char b = 2;
int c = a + b;
}
func void test5()
{
char a = 1;
int b = 2;
int c = a + b;
}
func void test6()
{
char a = 1;
char b = 2;
char c = (b > a) ? 1 : 0 + a + b;
}
func void test7()
{
int[100] array = { };
int v = array[1];
}
typedef int as Number;
func void test8()
{
Number a = 10;
char c = a; // #error: implicitly cast 'Number' (int) to 'char'
}
func void test9()
{
const char a = 1; // TODO should be "A"
char b = a;
a = b; // #error: Expression is not assignable
}
func void test10()
{
const char a = 1;
char* b = &a; // #error: address of values
}
enum Enum : int
{
A = 127,
B,
}
func void test11()
{
int a = Enum.A;
char b = Enum.B; // #error: Cannot implicitly convert 'Enum' with underlying type of 'int' to 'char'
}
func void test12()
{
float f = 3.14;
char a = f; // #error: cast 'float' to 'char'
}
func void test13()
{
int a = 1;
char b = a; // #error: cast 'int' to 'char'
}
func void test14()
{
byte a = 1;
char b = a; // #error: cast 'byte' to 'char'
}
func void test15()
{
float f = 3.14;
char c = 1;
char* a = &f; // #error: cast 'float*' to 'char*'
char* b = &c;
}
func void test16()
{
float f = 3.14;
int i = 1;
char c = 1 ? 'c' : 'd';
char d = 1 ? 'c' : i; // #error: cast 'int' to 'char'
char e = 1 ? i : 0; // #error: cast 'int' to 'char'
int g = 1 ? i : f; // #error: cast 'float' to 'int'
int a = f ? 1 : 0;
}
func void test17()
{
int a = "test"; // #error: cast 'string' to 'int'
}
func void test18()
{
char b = 1;
int a = b;
}
func void test19()
{
uint a = 1;
int b = a; // #error: cast 'uint' to 'int'
}
/*
const i32 Num = 200;
func void test1() {
i8 a = test.Num; // @error{constant value 200 out-of-bounds for type 'i8', range [-128, 127]}
}*/
func void test21()
{
int a = 1;
uint b = a; // #error: cast 'int' to 'uint'
}
func void foo() {}
func void test22()
{
char a = foo(); // #error: cast 'void' to 'char'
short b = foo(); // #error: cast 'void' to 'short'
int c = foo(); // #error: cast 'void' to 'int'
long d = foo(); // #error: cast 'void' to 'long'
byte e = foo(); // #error: cast 'void' to 'byte'
ushort f = foo(); // #error: cast 'void' to 'ushort'
uint g = foo(); // #error: cast 'void' to 'uint'
ulong h = foo(); // #error: cast 'void' to 'ulong'
bool i = foo(); // #error: cast 'void' to 'bool'
}
int num = 10;
func void test23()
{
int a = num;
int b = test::num;
char c = test::num; // #error: cast 'int' to 'char'
}
int[2][3] b123;
func void test24()
{
int a = b123; // #error: cast 'int[2][3]' to 'int'
}

View File

@@ -0,0 +1,34 @@
enum EnumTestOverflow
{
VALUE = 0x80000000, // #error: does not fit in type 'int'
}
enum EnumTestErrorType : float // #error: must be an integer type not 'float'
{
VALUE_BOOM
}
enum EnumWithErrorType2 : int* // #error: must be an integer type not 'int*'
{
TEST
}
enum EnumTestErrorType3 : int
{
A = FOO // #error: Identifier 'FOO' could not be found
}
func int foo()
{
return 10;
}
enum State
{
A = foo(), // #error: Expected a constant expression for enum
B = "hello", // #error: Cannot implicitly cast 'string' to 'int'
C = true, // #error: Cannot implicitly cast 'bool' to 'int'
}

View File

@@ -29,3 +29,18 @@ enum EnumTestSmall : ushort
VALUE = 0xFF,
VALUE2 = 0xFFFF
}
enum EnumWithErrorData2 : int (int bar, )
{
TEST
}
enum EnumTestErrorType4
{
}
enum EnumTest5
{
B = 0,
C,
}

View File

@@ -0,0 +1,23 @@
enum EnumWithErrorWithMissingName : int (int) // #error: function parameter must be named
{
TEST
}
enum EnumWithErrorData : int (int // #error: end of the parameter list
{
TEST
}
enum EnumWithErrorData2 : int (int, int bar) // #error: function parameter must be named
{
TEST
}
enum EnumTestErrorType3 : int
{
A,
A // #error: This enum constant is declared twice
}

View File

@@ -0,0 +1,17 @@
typedef int[4] as Arr;
Arr a = { 3, 4, 5, 6 };
func void test1()
{
Arr b = { 3, 4, 5, 6 };
int c = b; // #error: cast 'Arr' (int[4]) to 'int'
int d = a; // #error: cast 'Arr' (int[4]) to 'int'
}
typedef Number1 as Number2; // #error: Recursive definition of 'Number2'
typedef Number2 as Number1;
typedef Number as Number; // #error: Recursive definition of 'Number'

View File

@@ -0,0 +1,3 @@
func1 a = 1; // #error: declaration before the variable
func void func1() {}