From ed01616f1e4037171dd68628294f0055155e58cc Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Thu, 23 Jul 2020 17:59:42 +0200 Subject: [PATCH] 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. --- src/compiler/ast.c | 53 ++--- src/compiler/bigint.h | 1 + src/compiler/compiler.c | 2 +- src/compiler/compiler_internal.h | 31 +-- src/compiler/context.c | 2 +- src/compiler/diagnostics.c | 36 ++-- src/compiler/enums.h | 9 +- src/compiler/llvm_codegen.c | 3 +- src/compiler/llvm_codegen_debug_info.c | 2 - src/compiler/llvm_codegen_expr.c | 55 ++++-- src/compiler/llvm_codegen_function.c | 3 +- src/compiler/llvm_codegen_type.c | 18 +- src/compiler/parse_expr.c | 3 +- src/compiler/parser.c | 72 ++----- src/compiler/sema_casts.c | 6 +- src/compiler/sema_decls.c | 96 ++++++--- src/compiler/sema_expr.c | 160 ++++++++++----- src/compiler/sema_internal.h | 4 + src/compiler/sema_name_resolution.c | 38 +++- src/compiler/sema_passes.c | 3 + src/compiler/sema_stmts.c | 4 - src/compiler/sema_types.c | 5 - src/compiler/semantic_analyser.c | 8 +- src/compiler/types.c | 23 ++- test/src/tester.py | 6 +- test/test_suite/comments/simple_comments.c3 | 3 +- test/test_suite/enums/enum_errors.c3 | 11 -- test/test_suite/enums/enum_parse_errors.c3 | 19 -- test/test_suite/errors/error_decl_fails.c3 | 15 +- test/test_suite/errors/error_decl_ok.c3 | 11 ++ .../test_suite/errors/error_semantic_fails.c3 | 5 + test/test_suite/expressions/arithmetics.c3 | 11 ++ .../expressions/arithmetics_sema_fail.c3 | 129 ++++++++++++ test/test_suite/expressions/assign.c3 | 5 + test/test_suite/globals/global_init.c3 | 33 ++++ test/test_suite/globals/incr_array.c3 | 73 +++++++ test/test_suite/globals/incr_enum.c3 | 17 ++ test/test_suite/statements/for.c3 | 31 +++ test/test_suite/statements/for_errors.c3 | 7 + test/test_suite/statements/label_errors.c3 | 24 +++ test/test_suite/statements/switch_errors.c3 | 136 +++++++++++++ test/test_suite/struct/duplicate_member.c3 | 70 +++++++ test/test_suite/struct/member_access.c3 | 84 ++++++++ test/test_suite/symbols/various.c3 | 184 ++++++++++++++++++ test/test_suite/types/enum_errors.c3 | 34 ++++ test/test_suite/{enums => types}/enum_ok.c3 | 15 ++ test/test_suite/types/enum_parse_errors.c3 | 23 +++ test/test_suite/types/typedefs.c3 | 17 ++ test/test_suite/types/various.c3 | 3 + 49 files changed, 1289 insertions(+), 314 deletions(-) delete mode 100644 test/test_suite/enums/enum_errors.c3 delete mode 100644 test/test_suite/enums/enum_parse_errors.c3 create mode 100644 test/test_suite/errors/error_semantic_fails.c3 create mode 100644 test/test_suite/expressions/arithmetics_sema_fail.c3 create mode 100644 test/test_suite/expressions/assign.c3 create mode 100644 test/test_suite/globals/global_init.c3 create mode 100644 test/test_suite/globals/incr_array.c3 create mode 100644 test/test_suite/globals/incr_enum.c3 create mode 100644 test/test_suite/statements/for.c3 create mode 100644 test/test_suite/statements/for_errors.c3 create mode 100644 test/test_suite/statements/label_errors.c3 create mode 100644 test/test_suite/statements/switch_errors.c3 create mode 100644 test/test_suite/struct/duplicate_member.c3 create mode 100644 test/test_suite/struct/member_access.c3 create mode 100644 test/test_suite/symbols/various.c3 create mode 100644 test/test_suite/types/enum_errors.c3 rename test/test_suite/{enums => types}/enum_ok.c3 (74%) create mode 100644 test/test_suite/types/enum_parse_errors.c3 create mode 100644 test/test_suite/types/typedefs.c3 create mode 100644 test/test_suite/types/various.c3 diff --git a/src/compiler/ast.c b/src/compiler/ast.c index 330b349d9..73fa7602e 100644 --- a/src/compiler/ast.c +++ b/src/compiler/ast.c @@ -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) diff --git a/src/compiler/bigint.h b/src/compiler/bigint.h index b1cc8c68a..3ce7a403c 100644 --- a/src/compiler/bigint.h +++ b/src/compiler/bigint.h @@ -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); diff --git a/src/compiler/compiler.c b/src/compiler/compiler.c index bf46bbfbf..8992237f6 100644 --- a/src/compiler/compiler.c +++ b/src/compiler/compiler.c @@ -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); diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 8bc097dd1..43c611d74 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -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"; diff --git a/src/compiler/context.c b/src/compiler/context.c index fa1ce1a6e..b6ce6e75e 100644 --- a/src/compiler/context.c +++ b/src/compiler/context.c @@ -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; diff --git a/src/compiler/diagnostics.c b/src/compiler/diagnostics.c index be0447f40..75b0af83a 100644 --- a/src/compiler/diagnostics.c +++ b/src/compiler/diagnostics.c @@ -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); -} /* diff --git a/src/compiler/enums.h b/src/compiler/enums.h index d323c9bb3..bb4e56ef7 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -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 diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index 74dc4dacd..ffb886473 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -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 } diff --git a/src/compiler/llvm_codegen_debug_info.c b/src/compiler/llvm_codegen_debug_info.c index 5155679d8..a2a16a83c 100644 --- a/src/compiler/llvm_codegen_debug_info.c +++ b/src/compiler/llvm_codegen_debug_info.c @@ -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); diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index 1269a0374..eac1a97d4 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -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; } diff --git a/src/compiler/llvm_codegen_function.c b/src/compiler/llvm_codegen_function.c index a7842c20a..7847bdfd9 100644 --- a/src/compiler/llvm_codegen_function.c +++ b/src/compiler/llvm_codegen_function.c @@ -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: diff --git a/src/compiler/llvm_codegen_type.c b/src/compiler/llvm_codegen_type.c index 6b7ba52fc..74f7b3a2b 100644 --- a/src/compiler/llvm_codegen_type.c +++ b/src/compiler/llvm_codegen_type.c @@ -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: diff --git a/src/compiler/parse_expr.c b/src/compiler/parse_expr.c index a5e55eeb8..3c0ad105d 100644 --- a/src/compiler/parse_expr.c +++ b/src/compiler/parse_expr.c @@ -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); diff --git a/src/compiler/parser.c b/src/compiler/parser.c index 7bd2a6e7d..30a17ccd6 100644 --- a/src/compiler/parser.c +++ b/src/compiler/parser.c @@ -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)) { diff --git a/src/compiler/sema_casts.c b/src/compiler/sema_casts.c index 80a611e60..cad4d2740 100644 --- a/src/compiler/sema_casts.c +++ b/src/compiler/sema_casts.c @@ -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. diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index e834a7f1a..3b4651519 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -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: diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index f91f017ef..907a9fa4b 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -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) diff --git a/src/compiler/sema_internal.h b/src/compiler/sema_internal.h index be0e43d4a..04c3ffb87 100644 --- a/src/compiler/sema_internal.h +++ b/src/compiler/sema_internal.h @@ -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) diff --git a/src/compiler/sema_name_resolution.c b/src/compiler/sema_name_resolution.c index b8648d089..07ddf73b6 100644 --- a/src/compiler/sema_name_resolution.c +++ b/src/compiler/sema_name_resolution.c @@ -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); } diff --git a/src/compiler/sema_passes.c b/src/compiler/sema_passes.c index 554618e69..ae263c9a9 100644 --- a/src/compiler/sema_passes.c +++ b/src/compiler/sema_passes.c @@ -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]); diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index 520c67d07..433ec94ec 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -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) { diff --git a/src/compiler/sema_types.c b/src/compiler/sema_types.c index 246b56e7d..efa9887ff 100644 --- a/src/compiler/sema_types.c +++ b/src/compiler/sema_types.c @@ -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 diff --git a/src/compiler/semantic_analyser.c b/src/compiler/semantic_analyser.c index 22ad99b7b..1fe6c9b29 100644 --- a/src/compiler/semantic_analyser.c +++ b/src/compiler/semantic_analyser.c @@ -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); } diff --git a/src/compiler/types.c b/src/compiler/types.c index 75574b846..bcde01af5 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -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: diff --git a/test/src/tester.py b/test/src/tester.py index b11fe5279..e2028ffc4 100644 --- a/test/src/tester.py +++ b/test/src/tester.py @@ -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)) diff --git a/test/test_suite/comments/simple_comments.c3 b/test/test_suite/comments/simple_comments.c3 index 4e22e310f..61cab8561 100644 --- a/test/test_suite/comments/simple_comments.c3 +++ b/test/test_suite/comments/simple_comments.c3 @@ -10,4 +10,5 @@ module comments; func void test() { return; -} \ No newline at end of file +} + diff --git a/test/test_suite/enums/enum_errors.c3 b/test/test_suite/enums/enum_errors.c3 deleted file mode 100644 index 81d98223f..000000000 --- a/test/test_suite/enums/enum_errors.c3 +++ /dev/null @@ -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 -} \ No newline at end of file diff --git a/test/test_suite/enums/enum_parse_errors.c3 b/test/test_suite/enums/enum_parse_errors.c3 deleted file mode 100644 index 58dee5330..000000000 --- a/test/test_suite/enums/enum_parse_errors.c3 +++ /dev/null @@ -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; - } -} \ No newline at end of file diff --git a/test/test_suite/errors/error_decl_fails.c3 b/test/test_suite/errors/error_decl_fails.c3 index d4ac2e4d0..3be0547b7 100644 --- a/test/test_suite/errors/error_decl_fails.c3 +++ b/test/test_suite/errors/error_decl_fails.c3 @@ -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; + } +} \ No newline at end of file diff --git a/test/test_suite/errors/error_decl_ok.c3 b/test/test_suite/errors/error_decl_ok.c3 index 3cc9b3173..4ba94c05b 100644 --- a/test/test_suite/errors/error_decl_ok.c3 +++ b/test/test_suite/errors/error_decl_ok.c3 @@ -5,5 +5,16 @@ error TheError int a; } +error TheError2 +{ + byte a; + byte b; +} + +error TheError3 +{ + void *a; +} + error OtherError; diff --git a/test/test_suite/errors/error_semantic_fails.c3 b/test/test_suite/errors/error_semantic_fails.c3 new file mode 100644 index 000000000..1c9b3b5bf --- /dev/null +++ b/test/test_suite/errors/error_semantic_fails.c3 @@ -0,0 +1,5 @@ +error TooBig // #error: Error type may not exceed pointer +{ + usize a; + char b; +} diff --git a/test/test_suite/expressions/arithmetics.c3 b/test/test_suite/expressions/arithmetics.c3 index 5c640ba49..c1bae2c3e 100644 --- a/test/test_suite/expressions/arithmetics.c3 +++ b/test/test_suite/expressions/arithmetics.c3 @@ -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; } \ No newline at end of file diff --git a/test/test_suite/expressions/arithmetics_sema_fail.c3 b/test/test_suite/expressions/arithmetics_sema_fail.c3 new file mode 100644 index 000000000..ea6487dbd --- /dev/null +++ b/test/test_suite/expressions/arithmetics_sema_fail.c3 @@ -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' +} + diff --git a/test/test_suite/expressions/assign.c3 b/test/test_suite/expressions/assign.c3 new file mode 100644 index 000000000..4e6234c8f --- /dev/null +++ b/test/test_suite/expressions/assign.c3 @@ -0,0 +1,5 @@ +func void test1() +{ + int* p; + *p = 10; +} diff --git a/test/test_suite/globals/global_init.c3 b/test/test_suite/globals/global_init.c3 new file mode 100644 index 000000000..851463ff4 --- /dev/null +++ b/test/test_suite/globals/global_init.c3 @@ -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 \ No newline at end of file diff --git a/test/test_suite/globals/incr_array.c3 b/test/test_suite/globals/incr_array.c3 new file mode 100644 index 000000000..591ed0fbe --- /dev/null +++ b/test/test_suite/globals/incr_array.c3 @@ -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 } + diff --git a/test/test_suite/globals/incr_enum.c3 b/test/test_suite/globals/incr_enum.c3 new file mode 100644 index 000000000..1cf637ffc --- /dev/null +++ b/test/test_suite/globals/incr_enum.c3 @@ -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; diff --git a/test/test_suite/statements/for.c3 b/test/test_suite/statements/for.c3 new file mode 100644 index 000000000..00d8fe10a --- /dev/null +++ b/test/test_suite/statements/for.c3 @@ -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; +} +*/ \ No newline at end of file diff --git a/test/test_suite/statements/for_errors.c3 b/test/test_suite/statements/for_errors.c3 new file mode 100644 index 000000000..ba89a19a5 --- /dev/null +++ b/test/test_suite/statements/for_errors.c3 @@ -0,0 +1,7 @@ +func void foo() {} + +public func int main() +{ + for (; foo() ; ) {} // #error: Cannot implicitly cast 'void' to 'bool' + return 0; +} \ No newline at end of file diff --git a/test/test_suite/statements/label_errors.c3 b/test/test_suite/statements/label_errors.c3 new file mode 100644 index 000000000..3ed8c4e58 --- /dev/null +++ b/test/test_suite/statements/label_errors.c3 @@ -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' + } + } +} \ No newline at end of file diff --git a/test/test_suite/statements/switch_errors.c3 b/test/test_suite/statements/switch_errors.c3 new file mode 100644 index 000000000..0bd07e8e9 --- /dev/null +++ b/test/test_suite/statements/switch_errors.c3 @@ -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; + } +} \ No newline at end of file diff --git a/test/test_suite/struct/duplicate_member.c3 b/test/test_suite/struct/duplicate_member.c3 new file mode 100644 index 000000000..08d8245bc --- /dev/null +++ b/test/test_suite/struct/duplicate_member.c3 @@ -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' + } +} + diff --git a/test/test_suite/struct/member_access.c3 b/test/test_suite/struct/member_access.c3 new file mode 100644 index 000000000..d718c71d8 --- /dev/null +++ b/test/test_suite/struct/member_access.c3 @@ -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' +} + diff --git a/test/test_suite/symbols/various.c3 b/test/test_suite/symbols/various.c3 new file mode 100644 index 000000000..6cdc3f05e --- /dev/null +++ b/test/test_suite/symbols/various.c3 @@ -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' +} \ No newline at end of file diff --git a/test/test_suite/types/enum_errors.c3 b/test/test_suite/types/enum_errors.c3 new file mode 100644 index 000000000..8ac1b89bb --- /dev/null +++ b/test/test_suite/types/enum_errors.c3 @@ -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' +} diff --git a/test/test_suite/enums/enum_ok.c3 b/test/test_suite/types/enum_ok.c3 similarity index 74% rename from test/test_suite/enums/enum_ok.c3 rename to test/test_suite/types/enum_ok.c3 index 4fc723771..9e3b3a46e 100644 --- a/test/test_suite/enums/enum_ok.c3 +++ b/test/test_suite/types/enum_ok.c3 @@ -29,3 +29,18 @@ enum EnumTestSmall : ushort VALUE = 0xFF, VALUE2 = 0xFFFF } + +enum EnumWithErrorData2 : int (int bar, ) +{ + TEST +} + +enum EnumTestErrorType4 +{ +} + +enum EnumTest5 +{ + B = 0, + C, +} \ No newline at end of file diff --git a/test/test_suite/types/enum_parse_errors.c3 b/test/test_suite/types/enum_parse_errors.c3 new file mode 100644 index 000000000..c46dc3e8f --- /dev/null +++ b/test/test_suite/types/enum_parse_errors.c3 @@ -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 +} \ No newline at end of file diff --git a/test/test_suite/types/typedefs.c3 b/test/test_suite/types/typedefs.c3 new file mode 100644 index 000000000..a22cd8bad --- /dev/null +++ b/test/test_suite/types/typedefs.c3 @@ -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' + + diff --git a/test/test_suite/types/various.c3 b/test/test_suite/types/various.c3 new file mode 100644 index 000000000..584ddeb79 --- /dev/null +++ b/test/test_suite/types/various.c3 @@ -0,0 +1,3 @@ +func1 a = 1; // #error: declaration before the variable + +func void func1() {} \ No newline at end of file