diff --git a/src/compiler/ast.c b/src/compiler/ast.c index d918265b6..ff77d079b 100644 --- a/src/compiler/ast.c +++ b/src/compiler/ast.c @@ -1191,11 +1191,6 @@ static void fprint_ast_recursive(Context *context, FILE *file, Ast *ast, int ind DUMPEXPR(ast->assert_stmt.expr); DUMPEXPR(ast->assert_stmt.message); DUMPEND(); - case AST_TRY_STMT: - DUMP("(try"); - DUMPEXPR(ast->try_old_stmt.decl_expr); - DUMPAST(ast->try_old_stmt.body); - DUMPEND(); case AST_COMPOUND_STMT: if (!ast->compound_stmt.stmts) { @@ -1312,6 +1307,11 @@ static void fprint_ast_recursive(Context *context, FILE *file, Ast *ast, int ind DUMPEXPR(ast->switch_stmt.cond); DUMPASTS(ast->switch_stmt.cases); DUMPEND(); + case AST_IF_CATCH_SWITCH_STMT: + DUMP("(if-catch-switch"); + DUMPEXPR(ast->switch_stmt.cond); + DUMPASTS(ast->switch_stmt.cases); + DUMPEND(); case AST_CASE_STMT: DUMP("(case"); if (ast->case_stmt.is_type) @@ -1335,11 +1335,6 @@ static void fprint_ast_recursive(Context *context, FILE *file, Ast *ast, int ind DUMP("(asm"); // TODO DUMPEND(); - case AST_CATCH_STMT: - DUMP("(catch"); - DUMPEXPR(ast->catch_stmt.catchable); - DUMPAST(ast->catch_stmt.body); - DUMPEND(); case AST_CT_IF_STMT: DUMP("(ct-if"); DUMPEXPR(ast->ct_if_stmt.expr); diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index e1680e846..67c562a18 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -1124,25 +1124,6 @@ typedef struct } codegen; } AstDeferStmt; -typedef struct -{ - FlowCommon flow; - bool is_switch : 1; - bool has_err_var : 1; - Ast* scope_defer; - AstId defer; - union - { - Expr *catchable; - Decl *err_var; - }; - union - { - Ast *body; - Ast **cases; - }; - void *block; -} AstCatchStmt; typedef struct AstCtIfStmt_ @@ -1216,12 +1197,6 @@ typedef struct TokenId constraints; } AsmOperand; -typedef struct -{ - Expr *decl_expr; - Ast *body; -} AstTryStmt; - typedef struct { AsmOperand *inputs; @@ -1236,7 +1211,7 @@ typedef struct bool is_inline : 1; bool is_goto : 1; AsmParams *params; - TokenId **instructions; + Expr *body; } AstAsmStmt; typedef struct @@ -1286,7 +1261,6 @@ typedef struct Ast_ Ast** ct_compound_stmt; Decl *declare_stmt; // 8 Expr *expr_stmt; // 8 - AstTryStmt try_old_stmt; Ast *try_stmt; Decl *define_stmt; // 8 Ast *volatile_stmt; // 8 @@ -1300,7 +1274,6 @@ typedef struct Ast_ AstCtSwitchStmt ct_switch_stmt; // 16 AstContinueBreakStmt contbreak_stmt; // 8 AstNextStmt next_stmt; // 16 - AstCatchStmt catch_stmt; // 32 AstForStmt for_stmt; // 32 AstForeachStmt foreach_stmt; AstCtIfStmt ct_if_stmt; // 24 @@ -2258,10 +2231,6 @@ static inline Type *type_flatten(Type *type) type = type->decl->enums.type_info->type; continue; } - if (type->type_kind == TYPE_ANYERR || type->type_kind == TYPE_ERRTYPE) - { - type = type_iptr->canonical; - } return type; } } @@ -2314,6 +2283,7 @@ static inline Type *type_lowering(Type *type) Type *canonical = type_flatten(type); if (canonical->type_kind == TYPE_ENUM) return canonical->decl->enums.type_info->type->canonical; if (canonical->type_kind == TYPE_TYPEID) return type_iptr->canonical; + if (canonical->type_kind == TYPE_ANYERR) return type_iptr->canonical; if (canonical->type_kind == TYPE_ERRTYPE) return type_iptr->canonical; if (canonical->type_kind == TYPE_BITSTRUCT) return type_lowering(canonical->decl->bitstruct.base_type->type); return canonical; diff --git a/src/compiler/copying.c b/src/compiler/copying.c index 4580ca2dc..8f0bfb8af 100644 --- a/src/compiler/copying.c +++ b/src/compiler/copying.c @@ -272,25 +272,6 @@ Ast *copy_ast(Ast *source) MACRO_COPY_EXPR(ast->case_stmt.expr); } return ast; - case AST_CATCH_STMT: - copy_flow(ast); - if (ast->catch_stmt.has_err_var) - { - MACRO_COPY_DECL(ast->catch_stmt.err_var); - } - else - { - MACRO_COPY_EXPR(ast->catch_stmt.catchable); - } - if (ast->catch_stmt.is_switch) - { - MACRO_COPY_AST_LIST(ast->catch_stmt.cases); - } - else - { - MACRO_COPY_AST(ast->catch_stmt.body); - } - return ast; case AST_COMPOUND_STMT: MACRO_COPY_AST_LIST(ast->compound_stmt.stmts); return ast; @@ -377,14 +358,11 @@ Ast *copy_ast(Ast *source) MACRO_COPY_AST(ast->scoped_stmt.stmt); return ast; case AST_SWITCH_STMT: + case AST_IF_CATCH_SWITCH_STMT: copy_flow(ast); MACRO_COPY_EXPR(ast->switch_stmt.cond); MACRO_COPY_AST_LIST(ast->switch_stmt.cases); return ast; - case AST_TRY_STMT: - MACRO_COPY_EXPR(ast->try_old_stmt.decl_expr); - MACRO_COPY_AST(ast->try_old_stmt.body); - return ast; case AST_UNREACHABLE_STMT: return ast; case AST_VOLATILE_STMT: diff --git a/src/compiler/enums.h b/src/compiler/enums.h index 9965569f9..84c199ae6 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -48,7 +48,6 @@ typedef enum AST_ASSERT_STMT, AST_BREAK_STMT, AST_CASE_STMT, - AST_CATCH_STMT, AST_COMPOUND_STMT, AST_CONTINUE_STMT, AST_DEFINE_STMT, @@ -66,9 +65,9 @@ typedef enum AST_DOC_DIRECTIVE, AST_DOCS, AST_EXPR_STMT, - AST_TRY_STMT, AST_FOR_STMT, AST_FOREACH_STMT, + AST_IF_CATCH_SWITCH_STMT, AST_IF_STMT, AST_NOP_STMT, AST_RETURN_STMT, @@ -421,7 +420,6 @@ typedef enum TOKEN_BITSTRUCT, TOKEN_BREAK, TOKEN_CASE, - TOKEN_CATCH_OLD, TOKEN_CATCH, TOKEN_CONST, TOKEN_CONTINUE, @@ -451,7 +449,6 @@ typedef enum TOKEN_STRUCT, TOKEN_SWITCH, TOKEN_TRUE, - TOKEN_TRY_OLD, TOKEN_TRY, TOKEN_UNION, TOKEN_VAR, // Reserved diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index a3bb56032..594722505 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -777,7 +777,7 @@ void llvm_value_set_bool(BEValue *value, LLVMValueRef llvm_value) void llvm_value_set(BEValue *value, LLVMValueRef llvm_value, Type *type) { - type = type_flatten(type); + type = type_lowering(type); assert(llvm_value || type == type_void); value->value = llvm_value; value->alignment = type_abi_alignment(type); @@ -795,7 +795,7 @@ void llvm_value_set_address_align(BEValue *value, LLVMValueRef llvm_value, Type value->value = llvm_value; value->alignment = alignment; value->kind = BE_ADDRESS; - value->type = type_flatten(type); + value->type = type_lowering(type); } void llvm_value_set_decl_address(BEValue *value, Decl *decl) { @@ -812,7 +812,7 @@ void llvm_value_set_decl_address(BEValue *value, Decl *decl) void llvm_value_set_address(BEValue *value, LLVMValueRef llvm_value, Type *type) { - llvm_value_set_address_align(value, llvm_value, type_flatten(type), type_abi_alignment(type)); + llvm_value_set_address_align(value, llvm_value, type_lowering(type), type_abi_alignment(type)); } void llvm_value_fold_failable(GenContext *c, BEValue *value) diff --git a/src/compiler/llvm_codegen_c_abi_x64.c b/src/compiler/llvm_codegen_c_abi_x64.c index 9eb10471b..b239ffb14 100644 --- a/src/compiler/llvm_codegen_c_abi_x64.c +++ b/src/compiler/llvm_codegen_c_abi_x64.c @@ -539,7 +539,7 @@ AbiType *x64_get_sse_type_at_offset(Type *type, unsigned ir_offset, Type *source */ AbiType *x64_get_int_type_at_offset(Type *type, unsigned offset, Type *source_type, unsigned source_offset) { - type = type_flatten(type); + type = type_lowering(type); switch (type->type_kind) { case TYPE_U64: diff --git a/src/compiler/llvm_codegen_debug_info.c b/src/compiler/llvm_codegen_debug_info.c index 4cf808531..86e268a6c 100644 --- a/src/compiler/llvm_codegen_debug_info.c +++ b/src/compiler/llvm_codegen_debug_info.c @@ -373,13 +373,10 @@ static LLVMMetadataRef llvm_debug_subarray_type(GenContext *c, Type *type) static LLVMMetadataRef llvm_debug_errunion_type(GenContext *c, Type *type) { - LLVMMetadataRef forward = llvm_debug_forward_comp(c, type, type->name, NULL, NULL, LLVMDIFlagZero); - type->backend_debug_type = forward; - LLVMMetadataRef elements[2] = { - llvm_get_debug_member(c, type_usize, "domain", 0, NULL, forward, LLVMDIFlagZero), - llvm_get_debug_member(c, type_usize, "err", 0, NULL, forward, LLVMDIFlagZero) - }; - return llvm_get_debug_struct(c, type, type->name, elements, 2, NULL, NULL, LLVMDIFlagZero); + return LLVMDIBuilderCreateTypedef(c->debug.builder, + llvm_get_debug_type(c, type_iptr->canonical), + type->name, strlen(type->name), + NULL, 0, NULL, 0); } static LLVMMetadataRef llvm_debug_array_type(GenContext *c, Type *type) @@ -537,7 +534,6 @@ static inline LLVMMetadataRef llvm_get_debug_type_internal(GenContext *c, Type * case TYPE_SUBARRAY: return type->backend_debug_type = llvm_debug_subarray_type(c, type); case TYPE_ANYERR: - // TODO return type->backend_debug_type = llvm_debug_errunion_type(c, type); case TYPE_VIRTUAL: case TYPE_VIRTUAL_ANY: diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index 7891c8f45..898fbe0ed 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -338,7 +338,7 @@ static void llvm_emit_array_bounds_check(GenContext *c, BEValue *index, LLVMValu static inline LLVMValueRef llvm_emit_subscript_addr_with_base_new(GenContext *c, BEValue *parent, BEValue *index, SourceLocation *loc) { assert(llvm_value_is_addr(parent)); - Type *type = type_flatten(parent->type); + Type *type = type_lowering(parent->type); switch (type->type_kind) { case TYPE_POINTER: @@ -450,7 +450,7 @@ static inline void gencontext_emit_access_addr(GenContext *context, BEValue *be_ llvm_emit_expr(context, be_value, parent); Decl *member = expr->access_expr.ref; - gencontext_emit_member_addr(context, be_value, type_flatten(parent->type)->decl, member); + gencontext_emit_member_addr(context, be_value, type_lowering(parent->type)->decl, member); } static void gencontext_emit_scoped_expr(GenContext *context, BEValue *value, Expr *expr) @@ -500,16 +500,39 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, BEValue *value, Type *to_ switch (cast_kind) { - case CAST_ERBOOL: case CAST_EUINT: case CAST_ERINT: + to_type = type_lowering(to_type); + from_type = type_lowering(from_type); + llvm_value_rvalue(c, value); + if (type_convert_will_trunc(to_type, from_type)) + { + value->value = LLVMBuildTrunc(c->builder, value->value, llvm_get_type(c, to_type), "errinttrunc"); + } + else + { + value->value = type_is_signed(to_type) + ? LLVMBuildSExt(c->builder, value->value, llvm_get_type(c, to_type), "errsiext") + : LLVMBuildZExt(c->builder, value->value, llvm_get_type(c, to_type), "erruiext"); + + } + break; case CAST_VRBOOL: case CAST_VRPTR: case CAST_PTRVR: TODO case CAST_XIERR: - // TODO Insert zero check. + to_type = type_lowering(to_type); + from_type = type_lowering(from_type); llvm_value_rvalue(c, value); + if (type_convert_will_trunc(to_type, from_type)) + { + value->value = LLVMBuildTrunc(c->builder, value->value, llvm_get_type(c, to_type), "interrtrunc"); + } + else + { + value->value = LLVMBuildZExt(c->builder, value->value, llvm_get_type(c, to_type), "erruiext"); + } break; case CAST_ERROR: UNREACHABLE @@ -555,23 +578,14 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, BEValue *value, Type *to_ case CAST_ARRPTR: TODO case CAST_EREU: + // This is a no op. + assert(type_lowering(to_type) == type_lowering(from_type)); + break; case CAST_EUER: TODO // gencontext_emit_value_bitcast(c, value->value, to_type, from_type); + case CAST_ERBOOL: case CAST_EUBOOL: - if (value->kind == BE_VALUE) - { - value->value = LLVMBuildExtractValue(c->builder, value->value, 0, ""); - } - else - { - value->value = LLVMBuildStructGEP2(c->builder, llvm_get_type(c, type_anyerr), value->value, 0, ""); - value->value = llvm_emit_load_aligned(c, - llvm_get_type(c, type_usize), - value->value, - type_abi_alignment(type_usize), - ""); - } - value->value = LLVMBuildICmp(c->builder, LLVMIntNE, value->value, llvm_get_zero(c, type_usize), "eubool"); + value->value = llvm_emit_int_comparison(c, type_anyerr, type_anyerr, llvm_value_rvalue_store(c, value), llvm_get_zero(c, type_anyerr), BINARYOP_NE); value->kind = BE_BOOLEAN; break; case CAST_PTRBOOL: @@ -874,7 +888,7 @@ static inline void llvm_emit_initialize_reference_const(GenContext *c, BEValue * static inline void llvm_emit_initialize_reference_list(GenContext *c, BEValue *ref, Expr *expr) { // Getting ready to initialize, get the real type. - Type *real_type = type_flatten(ref->type); + Type *real_type = type_lowering(ref->type); Expr **elements = expr->initializer_expr.initializer_expr; // Make sure we have an address. @@ -1029,7 +1043,7 @@ static void llvm_emit_initialize_designated(GenContext *c, BEValue *ref, uint64_ static inline void llvm_emit_initialize_reference_designated(GenContext *c, BEValue *ref, Expr *expr) { // Getting ready to initialize, get the real type. - Type *real_type = type_flatten(ref->type); + Type *real_type = type_lowering(ref->type); Expr **elements = expr->initializer_expr.initializer_expr; assert(vec_size(elements)); @@ -1245,7 +1259,7 @@ static void gencontext_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr llvm_value_addr(c, value); // Transform to value value->kind = BE_VALUE; - value->type = type_flatten(expr->type); + value->type = type_lowering(expr->type); return; case UNARYOP_DEREF: llvm_emit_expr(c, value, expr->unary_expr.expr); @@ -1253,7 +1267,7 @@ static void gencontext_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr llvm_value_rvalue(c, value); // Convert pointer to address value->kind = BE_ADDRESS; - value->type = type_flatten(expr->type); + value->type = type_lowering(expr->type); return; case UNARYOP_INC: llvm_emit_pre_inc_dec(c, value, expr->unary_expr.expr, 1, false); @@ -2573,7 +2587,7 @@ static void gencontext_expand_struct_to_args(GenContext *context, Type *param_ty static void llvm_expand_type_to_args(GenContext *context, Type *param_type, LLVMValueRef expand_ptr, LLVMValueRef **values) { REDO: - switch (type_flatten(param_type)->type_kind) + switch (type_lowering(param_type)->type_kind) { case TYPE_POISONED: case TYPE_VOID: diff --git a/src/compiler/llvm_codegen_stmt.c b/src/compiler/llvm_codegen_stmt.c index 044e0fd66..8b655c680 100644 --- a/src/compiler/llvm_codegen_stmt.c +++ b/src/compiler/llvm_codegen_stmt.c @@ -4,8 +4,6 @@ #include "llvm_codegen_internal.h" -void gencontext_emit_try_stmt(GenContext *context, Ast *pAst); - static bool ast_is_not_empty(Ast *ast) { @@ -94,7 +92,7 @@ LLVMValueRef llvm_emit_local_decl(GenContext *c, Decl *decl) } else { - Type *type = type_flatten(decl->type); + Type *type = type_lowering(decl->type); // Normal case, zero init. if (type_is_builtin(type->type_kind) || type->type_kind == TYPE_POINTER) { @@ -144,7 +142,7 @@ void gencontext_emit_decl_expr_list(GenContext *context, BEValue *be_value, Expr } if (bool_cast) { - type = type_flatten(type); + type = type_lowering(type); if (type->type_kind != TYPE_BOOL) { CastKind cast = cast_to_bool_kind(type); @@ -471,7 +469,7 @@ static void llvm_emit_foreach_stmt(GenContext *c, Ast *ast) LLVMTypeRef actual_type_llvm = llvm_get_type(c, actual_type); llvm_emit_local_var_alloca(c, ast->foreach_stmt.variable); - Type *var_type = type_flatten(ast->foreach_stmt.variable->type); + Type *var_type = type_lowering(ast->foreach_stmt.variable->type); LLVMTypeRef var_type_llvm = llvm_get_type(c, var_type); BEValue var; llvm_value_set_address(&var, ast->foreach_stmt.variable->backend_ref, var_type); @@ -955,52 +953,6 @@ void gencontext_emit_scoped_stmt(GenContext *context, Ast *ast) llvm_emit_defer(context, ast->scoped_stmt.defers.start, ast->scoped_stmt.defers.end); } -void gencontext_emit_try_stmt(GenContext *c, Ast *ast) -{ - // Create after try block - LLVMBasicBlockRef after_try = llvm_basic_block_new(c, "after_try"); - EMIT_LOC(c, ast); - - // Store catch/error var - PUSH_ERROR(); - - // Set the catch/error var - c->error_var = NULL; - c->catch_block = after_try; - - // Emit the checks, which will create jumps like we want them. - TODO - Ast **decl_expr = NULL; // ast->try_old_stmt.decl_expr->dexpr_list_expr; - BEValue be_value; - VECEACH(decl_expr, i) - { - Ast *dexpr = decl_expr[i]; - switch (dexpr->ast_kind) - { - case AST_EXPR_STMT: - llvm_emit_expr(c, &be_value, dexpr->expr_stmt); - llvm_value_rvalue(c, &be_value); - break; - case AST_DECLARE_STMT: - //TODO llvm_emit_local_decl(c, dexpr); - break; - default: - UNREACHABLE - } - } - - // Restore. - POP_ERROR(); - - // Emit the statement - llvm_emit_stmt(c, ast->try_old_stmt.body); - - // Jump to after. - llvm_emit_br(c, after_try); - llvm_emit_block(c, after_try); - -} - static inline void llvm_emit_assume(GenContext *c, Expr *expr) { @@ -1077,6 +1029,41 @@ static inline void llvm_emit_assert_stmt(GenContext *c, Ast *ast) llvm_emit_assume(c, ast->assert_stmt.expr); } +static inline void add_target_clobbers_to_buffer(GenContext *c) +{ + switch (platform_target.arch) + { + case ARCH_TYPE_X86_64: + case ARCH_TYPE_X86: + scratch_buffer_append("~{dirflag},~{fpsr},~{flags}"); + break; + case ARCH_TYPE_MIPS: + case ARCH_TYPE_MIPS64: + case ARCH_TYPE_MIPS64EL: + case ARCH_TYPE_MIPSEL: + // Currently Clang does this + scratch_buffer_append("~{$1}"); + break; + default: + // In Clang no other platform has automatic clobbers + break; + } +} +static inline void llvm_emit_asm_stmt(GenContext *c, Ast *ast) +{ + LLVMTypeRef asm_fn_type = LLVMFunctionType(llvm_get_type(c, type_void), NULL, 0, 0); + scratch_buffer_clear(); + add_target_clobbers_to_buffer(c); + LLVMValueRef asm_fn = LLVMGetInlineAsm(asm_fn_type, + (char *)ast->asm_stmt.body->const_expr.string.chars, + ast->asm_stmt.body->const_expr.string.len, + scratch_buffer_to_string(), global_context.scratch_buffer_len, + ast->asm_stmt.is_volatile, + true, + LLVMInlineAsmDialectIntel); + LLVMBuildCall2(c->builder, asm_fn_type, asm_fn, NULL, 0, ""); +} + static inline void gencontext_emit_unreachable_stmt(GenContext *context, Ast *ast) { SourceLocation *loc = TOKLOC(ast->span.loc); @@ -1110,67 +1097,6 @@ void gencontext_emit_expr_stmt(GenContext *c, Ast *ast) llvm_value_rvalue(c, &value); } -void gencontext_emit_catch_stmt(GenContext *c, Ast *ast) -{ - Expr *catch_expr; - LLVMValueRef error_result = NULL; - if (ast->catch_stmt.has_err_var) - { - Decl *error_var = ast->catch_stmt.err_var; - assert(error_var->type->canonical == type_anyerr); - error_result = llvm_emit_alloca_aligned(c, type_anyerr, error_var->name); - error_var->backend_ref = error_result; - catch_expr = error_var->var.init_expr; - - } - else - { - if (ast->catch_stmt.is_switch) - { - error_result = llvm_emit_alloca_aligned(c, type_anyerr, "catchval"); - } - catch_expr = ast->catch_stmt.catchable; - } - - // Create catch block. - LLVMBasicBlockRef catch_block = llvm_basic_block_new(c, "catch"); - - // Store catch/error var - PUSH_ERROR(); - - // Set the catch/error var - c->error_var = error_result; - c->catch_block = catch_block; - - // Emit the catch, which will create jumps like we want them. - BEValue value; - llvm_emit_expr(c, &value, catch_expr); - llvm_value_fold_failable(c, &value); - - // Restore. - POP_ERROR(); - - // Create the bloch after and jump to it. - LLVMBasicBlockRef after_catch = llvm_basic_block_new(c, "after_catch"); - llvm_emit_br(c, after_catch); - - // Emit catch. - llvm_emit_block(c, catch_block); - - if (ast->catch_stmt.is_switch) - { - LLVMValueRef ref = llvm_emit_bitcast(c, error_result, type_get_ptr(type_typeid)); - gencontext_emit_if_switch_body(c, gencontext_emit_load(c, type_typeid, ref), ast->catch_stmt.cases); - } - else - { - llvm_emit_stmt(c, ast->catch_stmt.body); - } - - // Jump to after. - llvm_emit_br(c, after_catch); - llvm_emit_block(c, after_catch); -} static LLVMValueRef llvm_emit_string(GenContext *c, const char *str) { LLVMTypeRef char_type = llvm_get_type(c, type_char); @@ -1327,10 +1253,8 @@ void llvm_emit_stmt(GenContext *c, Ast *ast) case AST_DOC_DIRECTIVE: case AST_POISONED: case AST_DEFINE_STMT: + case AST_IF_CATCH_SWITCH_STMT: UNREACHABLE - case AST_TRY_STMT: - gencontext_emit_try_stmt(c, ast); - break; case AST_SCOPED_STMT: gencontext_emit_scoped_stmt(c, ast); break; @@ -1376,11 +1300,9 @@ void llvm_emit_stmt(GenContext *c, Ast *ast) case AST_DEFER_STMT: case AST_NOP_STMT: break; - case AST_CATCH_STMT: - gencontext_emit_catch_stmt(c, ast); - break; case AST_ASM_STMT: - TODO + llvm_emit_asm_stmt(c, ast); + break; case AST_ASSERT_STMT: llvm_emit_assert_stmt(c, ast); break;; diff --git a/src/compiler/llvm_codegen_type.c b/src/compiler/llvm_codegen_type.c index e56fb7d18..70f1449fd 100644 --- a/src/compiler/llvm_codegen_type.c +++ b/src/compiler/llvm_codegen_type.c @@ -314,7 +314,7 @@ LLVMTypeRef llvm_get_type(GenContext *c, Type *any_type) case TYPE_TYPEID: case TYPE_ANYERR: case TYPE_ERRTYPE: - return any_type->backend_type = llvm_get_type(c, type_iptr); + return any_type->backend_type = llvm_get_type(c, type_iptr->canonical); case TYPE_TYPEDEF: return any_type->backend_type = llvm_get_type(c, any_type->canonical); case TYPE_DISTINCT: diff --git a/src/compiler/parse_stmt.c b/src/compiler/parse_stmt.c index 0ccf1c4bd..64f61880e 100644 --- a/src/compiler/parse_stmt.c +++ b/src/compiler/parse_stmt.c @@ -137,46 +137,22 @@ static inline bool parse_asm_params(Context *context, Ast *asm_ast) TODO } /** - * asm { ... } + * asm ::= 'asm' '(' string ')' * @param context * @return */ static inline Ast* parse_asm_stmt(Context *context) { - TODO - /* Ast *ast = AST_NEW_TOKEN(AST_ASM_STMT, context->tok); advance_and_verify(context, TOKEN_ASM); - if (try_consume(context, TOKEN_LPAREN)) - { - if (!parse_asm_params(context, ast)) return poisoned_ast; - } - - if (!TOKEN_IS(TOKEN_LBRACE)) - { - SEMA_TOKEN_ERROR(context->tok, "Expected '{' to start asm segment."); - return poisoned_ast; - } - context->lexer.current = context->next_tok->span.loc + context->lexer.file_begin; - while (1) - { - TODO - //context->tok = lexer_scan_asm(&context->lexer); - TokenType type = context->tok.type; - if (type == TOKEN_RBRACE || type == TOKEN_EOF) break; - context->prev_tok_end = context->token->span.end_loc; - vec_add(ast->asm_stmt.instructions, context->token); - } - if (TOKEN_IS(TOKEN_EOF)) - { - sema_error_at(context->prev_tok_end, "Unexpected end of file while parsing asm, did you forget a '}'?"); - return poisoned_ast; - } - assert(TOKEN_IS(TOKEN_RBRACE)); - //context->tok = lexer_scan_token(&context->lexer); - //context->next_tok = lexer_scan_token(&context->lexer); + ast->asm_stmt.is_volatile = try_consume(context, TOKEN_VOLATILE); + CONSUME_OR(TOKEN_LPAREN, poisoned_ast); + ast->asm_stmt.body = TRY_EXPR_OR(parse_expr(context), poisoned_ast); + ast->asm_stmt.is_volatile = true; + CONSUME_OR(TOKEN_RPAREN, poisoned_ast); + RANGE_EXTEND_PREV(ast); + CONSUME_OR(TOKEN_EOS, poisoned_ast); return ast; - */ } @@ -222,36 +198,6 @@ static inline Ast *parse_case_stmts(Context *context, TokenType case_type, Token } -/** - * catch_stmt - * : CATCH '(' expression ')' catch_body - * | CATCH '(' expression ')' compound_stmt - * ; - */ -static inline Ast* parse_catch_stmt(Context *context) -{ - Ast *catch_stmt = AST_NEW_TOKEN(AST_CATCH_STMT, context->tok); - advance_and_verify(context, TOKEN_CATCH_OLD); - - catch_stmt->catch_stmt.flow.label = TRY_DECL_OR(parse_optional_label(context, catch_stmt), false); - - CONSUME_OR(TOKEN_LPAREN, poisoned_ast); - - catch_stmt->catch_stmt.catchable = TRY_EXPR_OR(parse_expr(context), poisoned_ast); - - CONSUME_OR(TOKEN_RPAREN, poisoned_ast); - - if (TOKEN_IS(TOKEN_LBRACE) && (context->next_tok.type == TOKEN_CASE || context->next_tok.type == TOKEN_DEFAULT)) - { - catch_stmt->catch_stmt.is_switch = true; - if (!parse_switch_body(context, &catch_stmt->catch_stmt.cases, TOKEN_CASE, TOKEN_DEFAULT, false)) return poisoned_ast; - return catch_stmt; - } - - catch_stmt->catch_stmt.body = TRY_AST(parse_stmt(context)); - - return catch_stmt; -} /** * defer_stmt @@ -310,8 +256,19 @@ static inline Ast* parse_if_stmt(Context *context) CONSUME_OR(TOKEN_LPAREN, poisoned_ast); if_ast->if_stmt.cond = TRY_EXPR_OR(parse_cond(context), poisoned_ast); CONSUME_OR(TOKEN_RPAREN, poisoned_ast); - Ast *stmt = TRY_AST(parse_stmt(context)); - if_ast->if_stmt.then_body = stmt; + // Special case, we might have if ( ) { case ... } + if (tok_is(context, TOKEN_LBRACE) && (context->next_tok.type == TOKEN_CASE || context->next_tok.type == TOKEN_DEFAULT)) + { + Ast *stmt = AST_NEW_TOKEN(AST_IF_CATCH_SWITCH_STMT, context->tok); + Ast **cases = NULL; + if (!parse_switch_body(context, &cases, TOKEN_CASE, TOKEN_DEFAULT, true)) return poisoned_ast; + stmt->switch_stmt.cases = cases; + if_ast->if_stmt.then_body = stmt; + } + else + { + if_ast->if_stmt.then_body = TRY_AST(parse_stmt(context)); + } if (!try_consume(context, TOKEN_ELSE)) { return if_ast; @@ -635,22 +592,6 @@ static inline Ast *parse_expr_stmt(Context *context) } -/** - * try_stmt - * : try '(' decl_expr ')' statement - * ; - */ -static inline Ast *parse_try_stmt(Context *context) -{ - Ast *stmt = AST_NEW_TOKEN(AST_TRY_STMT, context->tok); - advance_and_verify(context, TOKEN_TRY_OLD); - TRY_CONSUME(TOKEN_LPAREN, "Expected a '(' after 'try'."); - stmt->try_old_stmt.decl_expr = TRY_EXPR_OR(parse_cond(context), poisoned_ast); - TRY_CONSUME(TOKEN_RPAREN, "Expected a ')' after 'try'."); - stmt->try_old_stmt.body = TRY_AST(parse_stmt(context)); - return stmt; -} - static inline Ast *parse_decl_or_expr_stmt(Context *context) { @@ -963,8 +904,6 @@ Ast *parse_stmt(Context *context) case TOKEN_IDENT: case TOKEN_CONST_IDENT: return parse_decl_or_expr_stmt(context); - case TOKEN_TRY_OLD: - return parse_try_stmt(context); case TOKEN_DEFINE: return parse_define_stmt(context); case TOKEN_STATIC: // Static means declaration! @@ -991,8 +930,6 @@ Ast *parse_stmt(Context *context) return parse_for_stmt(context); case TOKEN_FOREACH: return parse_foreach_stmt(context); - case TOKEN_CATCH_OLD: - return parse_catch_stmt(context); case TOKEN_CONTINUE: { Ast *ast = TRY_AST(parse_continue(context)); diff --git a/src/compiler/sema_casts.c b/src/compiler/sema_casts.c index 7197aebb2..66b19afcc 100644 --- a/src/compiler/sema_casts.c +++ b/src/compiler/sema_casts.c @@ -769,7 +769,7 @@ bool cast_implicit_bit_width(Expr *expr, Type *to_type) bool cast(Expr *expr, Type *to_type) { Type *from_type = type_flatten(expr->type->canonical); - Type *canonical = type_lowering(to_type); + Type *canonical = type_flatten(to_type); if (from_type == canonical) { expr_set_type(expr, to_type); diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index f7aeeeffa..04b761be9 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -1335,7 +1335,7 @@ static inline bool sema_analyse_if_stmt(Context *context, Ast *statement) success = false; } } - if (success && statement->if_stmt.then_body->ast_kind != AST_COMPOUND_STMT) + if (success && statement->if_stmt.then_body->ast_kind != AST_COMPOUND_STMT && statement->if_stmt.then_body->ast_kind != AST_IF_CATCH_SWITCH_STMT) { SourceLocation *end_of_cond = TOKLOC(cond->span.end_loc); SourceLocation *start_of_then = TOKLOC(statement->if_stmt.then_body->span.loc); @@ -1387,9 +1387,16 @@ static inline bool sema_analyse_if_stmt(Context *context, Ast *statement) -static bool sema_analyse_asm_stmt(Context *context __unused, Ast *statement __unused) +static bool sema_analyse_asm_stmt(Context *context, Ast *stmt) { - TODO + if (!sema_analyse_expr(context, NULL, stmt->asm_stmt.body)) return false; + if (stmt->asm_stmt.body->expr_kind != EXPR_CONST + || stmt->asm_stmt.body->const_expr.kind != TYPE_STRLIT) + { + SEMA_ERROR(stmt->asm_stmt.body, "The asm statement requires a constant string here."); + return false; + } + return true; } static inline Decl *sema_analyse_label(Context *context, Ast *stmt) @@ -1486,20 +1493,13 @@ static bool sema_analyse_next_stmt(Context *context, Ast *statement) } parent = astptr(target->label.parent); AstKind kind = parent->ast_kind; - if (kind != AST_SWITCH_STMT && kind != AST_CATCH_STMT) + if (kind != AST_SWITCH_STMT) { SEMA_TOKID_ERROR(statement->next_stmt.label.span, "Expected the label to match a 'switch' or 'catch' statement."); return false; } bool defer_mismatch = false; - if (parent->ast_kind == AST_SWITCH_STMT) - { - defer_mismatch = context->active_scope.in_defer != parent->switch_stmt.scope_defer; - } - else - { - defer_mismatch = context->active_scope.in_defer != parent->catch_stmt.scope_defer; - } + defer_mismatch = context->active_scope.in_defer != parent->switch_stmt.scope_defer; if (defer_mismatch) { SEMA_ERROR(statement, "This 'next' would jump out of a defer which is not allowed."); @@ -1526,22 +1526,14 @@ static bool sema_analyse_next_stmt(Context *context, Ast *statement) { if (!sema_resolve_type_info(context, statement->next_stmt.type_info)) return false; Ast **cases; - if (parent->ast_kind == AST_SWITCH_STMT) + statement->next_stmt.defers.end = parent->switch_stmt.defer; + if (parent->switch_stmt.cond->type->canonical != type_typeid) { - statement->next_stmt.defers.end = parent->switch_stmt.defer; - if (parent->switch_stmt.cond->type->canonical != type_typeid) - { - SEMA_ERROR(statement, "Unexpected 'type' in as an 'next' destination."); - SEMA_PREV(statement, "The 'switch' here uses expected a type '%s'.", type_to_error_string(parent->switch_stmt.cond->type)); - return false; - } - cases = parent->switch_stmt.cases; - } - else - { - statement->next_stmt.defers.end = parent->catch_stmt.defer; - cases = parent->catch_stmt.cases; + SEMA_ERROR(statement, "Unexpected 'type' in as an 'next' destination."); + SEMA_PREV(statement, "The 'switch' here uses expected a type '%s'.", type_to_error_string(parent->switch_stmt.cond->type)); + return false; } + cases = parent->switch_stmt.cases; Ast *default_stmt = NULL; VECEACH(cases, i) @@ -1806,13 +1798,13 @@ static bool sema_analyse_switch_body(Context *context, Ast *statement, SourceSpa switch (switch_type_flattened->type_kind) { case TYPE_TYPEID: - case TYPE_ANYERR: use_type_id = true; break; case ALL_INTS: assert(switch_type->type_kind != TYPE_IXX); case TYPE_BOOL: case TYPE_ENUM: + case TYPE_ANYERR: break; case TYPE_DISTINCT: UNREACHABLE @@ -1985,21 +1977,31 @@ static bool sema_analyse_ct_switch_stmt(Context *context, Ast *statement) static bool sema_analyse_switch_stmt(Context *context, Ast *statement) { statement->switch_stmt.scope_defer = context->active_scope.in_defer; + + SCOPE_START_WITH_LABEL(statement->switch_stmt.flow.label); + Expr *cond = statement->switch_stmt.cond; - if (!sema_analyse_cond(context, cond, false)) return false; + Type *switch_type; + if (statement->ast_kind == AST_SWITCH_STMT) + { + if (!sema_analyse_cond(context, cond, false)) return false; + switch_type = VECLAST(cond->cond_expr)->type->canonical; + } + else + { + switch_type = type_anyerr; + } - Type *switch_type = VECLAST(cond->cond_expr)->type->canonical; statement->switch_stmt.defer = context->active_scope.defer_last; - if (!sema_analyse_switch_body(context, statement, cond->span, + if (!sema_analyse_switch_body(context, statement, cond ? cond->span : statement->span, switch_type->canonical, statement->switch_stmt.cases)) { return SCOPE_POP_ERROR(); } context_pop_defers_and_replace_ast(context, statement); - SCOPE_END; if (statement->flow.no_exit && !statement->flow.has_break) @@ -2009,159 +2011,7 @@ static bool sema_analyse_switch_stmt(Context *context, Ast *statement) return true; } -/** - * Handle the catch statement - * @return true if error checking succeeds. - */ -static bool sema_analyse_catch_stmt(Context *context, Ast *statement) -{ - Expr *catch_expr = statement->catch_stmt.catchable; - Decl *error_var = NULL; - Expr *error_expr = catch_expr; - Decl *unwrapped = NULL; - statement->catch_stmt.scope_defer = context->active_scope.in_defer; - SCOPE_START_WITH_LABEL(statement->catch_stmt.flow.label); - - statement->catch_stmt.defer = context->active_scope.defer_last; - - if (catch_expr->expr_kind == EXPR_BINARY && catch_expr->binary_expr.operator == BINARYOP_ASSIGN) - { - Expr *left = catch_expr->binary_expr.left; - if (left->expr_kind == EXPR_IDENTIFIER) - { - Decl *ambiguous_decl; - Decl *dummy; - Decl *error_var_decl = sema_resolve_normal_symbol(context, - left->identifier_expr.identifier, - left->identifier_expr.path, false); - if (!error_var_decl) - { - error_var = decl_new_var(left->span.loc, type_info_new_base(type_anyerr, left->span), VARDECL_LOCAL, - VISIBLE_LOCAL); - error_var->type = type_anyerr; - Expr *right = catch_expr->binary_expr.right; - error_var->var.init_expr = right; - error_expr = right; - statement->catch_stmt.has_err_var = true; - statement->catch_stmt.err_var = error_var; - } - } - } - - if (!sema_analyse_expr(context, NULL, error_expr)) return SCOPE_POP_ERROR(); - - if (error_var) - { - sema_add_local(context, error_var); - } - - if (!error_expr->failable) - { - const char *error_type = type_to_error_string(error_expr->type); - if (error_expr->expr_kind == EXPR_IDENTIFIER - && error_expr->identifier_expr.decl->decl_kind == DECL_VAR - && error_expr->identifier_expr.decl->var.kind == VARDECL_UNWRAPPED) - { - SEMA_ERROR(error_expr, - "'%s' is unwrapped to '%s' here, so it cannot be caught.", - error_expr->identifier_expr.decl->name, - error_type); - } - else - { - SEMA_ERROR(error_expr, "Expected a failable '%s!' not '%s'.", error_type, error_type); - } - return SCOPE_POP_ERROR(); - } - - if (catch_expr->expr_kind == EXPR_IDENTIFIER) - { - unwrapped = catch_expr->identifier_expr.decl; - } - else if (error_var) - { - Expr *right = catch_expr->binary_expr.right; - if (right->expr_kind == EXPR_IDENTIFIER) unwrapped = right->identifier_expr.decl; - } - - if (statement->catch_stmt.is_switch) - { - if (!sema_analyse_switch_body(context, - statement, - error_expr->span, - type_anyerr, - statement->catch_stmt.cases)) - { - return SCOPE_POP_ERROR(); - } - } - else - { - if (!sema_analyse_statement(context, statement->catch_stmt.body)) return SCOPE_POP_ERROR(); - if (context->active_scope.jump_end) statement->flow.no_exit = true; - } - context_pop_defers_and_replace_ast(context, statement); - - SCOPE_END; - - if (unwrapped && !statement->flow.has_break && statement->flow.no_exit) - { - Decl *decl = decl_copy(unwrapped); - decl->var.kind = VARDECL_UNWRAPPED; - decl->var.alias = unwrapped; - decl->var.failable = false; - sema_unwrap_var(context, decl); - } - return true; -} - - -static bool sema_analyse_try_stmt(Context *context, Ast *stmt) -{ - assert(stmt->try_old_stmt.decl_expr->expr_kind == EXPR_COND); - - Expr **dexprs = stmt->try_old_stmt.decl_expr->cond_expr; - TODO - /*TODO - SCOPE_START - unsigned entries = vec_size(dexprs); - for (unsigned i = 0; i < entries; i++) - { - Ast *ast = dexprs[i]; - if (ast->ast_kind == AST_DECLARE_STMT) - { - ast->declare_stmt->var.unwrap = true; - if (!sema_analyse_statement(context, ast)) return SCOPE_POP_ERROR(); - continue; - } - - if (!sema_analyse_statement(context, ast)) return SCOPE_POP_ERROR(); - - Expr *expr = ast->expr_stmt; - if (!expr->failable) - { - SEMA_ERROR(expr, "The expression to 'try' must be failable."); - return SCOPE_POP_ERROR(); - } - if (expr->expr_kind == EXPR_IDENTIFIER) - { - Decl *var = expr->identifier_expr.decl; - Decl *decl = decl_copy(var); - decl->var.kind = VARDECL_ALIAS; - decl->var.alias = var; - decl->var.failable = false; - sema_unwrap_var(context, decl); - } - } - if (!sema_analyse_statement(context, stmt->try_old_stmt.body)) - { - return SCOPE_POP_ERROR(); - } - SCOPE_END; - */ - return true; -} static bool sema_analyse_volatile_stmt(Context *context, Ast *statement) { @@ -2285,8 +2135,6 @@ static inline bool sema_analyse_statement_inner(Context *context, Ast *statement case AST_CASE_STMT: SEMA_ERROR(statement, "Unexpected 'case' outside of switch"); return false; - case AST_CATCH_STMT: - return sema_analyse_catch_stmt(context, statement); case AST_COMPOUND_STMT: return sema_analyse_compound_stmt(context, statement); case AST_CONTINUE_STMT: @@ -2314,8 +2162,6 @@ static inline bool sema_analyse_statement_inner(Context *context, Ast *statement return sema_analyse_foreach_stmt(context, statement); case AST_FOR_STMT: return sema_analyse_for_stmt(context, statement); - case AST_TRY_STMT: - return sema_analyse_try_stmt(context, statement); case AST_IF_STMT: return sema_analyse_if_stmt(context, statement); case AST_NOP_STMT: @@ -2323,6 +2169,7 @@ static inline bool sema_analyse_statement_inner(Context *context, Ast *statement case AST_RETURN_STMT: return sema_analyse_return_stmt(context, statement); case AST_SWITCH_STMT: + case AST_IF_CATCH_SWITCH_STMT: return sema_analyse_switch_stmt(context, statement); case AST_NEXT_STMT: return sema_analyse_next_stmt(context, statement); diff --git a/src/compiler/tokens.c b/src/compiler/tokens.c index 2cb5df578..5fbcfe788 100644 --- a/src/compiler/tokens.c +++ b/src/compiler/tokens.c @@ -194,8 +194,6 @@ const char *token_type_to_string(TokenType type) return "break"; case TOKEN_CASE: return "case"; - case TOKEN_CATCH_OLD: - return "catchx"; case TOKEN_CATCH: return "catch"; case TOKEN_CONST: @@ -254,8 +252,6 @@ const char *token_type_to_string(TokenType type) return "switch"; case TOKEN_TRUE: return "true"; - case TOKEN_TRY_OLD: - return "tryx"; case TOKEN_TRY: return "try"; case TOKEN_TYPEID: diff --git a/src/compiler/types.c b/src/compiler/types.c index 5013ec98b..accf10697 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -256,13 +256,13 @@ bool type_is_union_struct(Type *type) bool type_is_empty_field(Type *type, bool allow_array) { - type = type_flatten(type); + type = type_lowering(type); if (allow_array) { while (type->type_kind == TYPE_ARRAY) { if (type->array.len == 0) return true; - type = type_flatten(type->array.base); + type = type_lowering(type->array.base); } } return type_is_empty_record(type, allow_array); @@ -303,7 +303,7 @@ Type *type_abi_find_single_struct_element(Type *type) Decl **members = type->decl->strukt.members; VECEACH(members, i) { - Type *field_type = type_flatten(members[i]->type); + Type *field_type = type_lowering(members[i]->type); // Ignore empty arrays if (type_is_empty_field(field_type, true)) continue; @@ -626,7 +626,7 @@ AlignSize type_alloca_alignment(Type *type) { if (platform_target.abi == ABI_X64) { - type = type_flatten(type); + type = type_lowering(type); if (type->type_kind == TYPE_ARRAY && type_size(type) >= 16) return 16; } return type_abi_alignment(type); diff --git a/test/test_suite/errors/try_assign.c3t b/test/test_suite/errors/try_assign.c3t index e7b1d7016..7df31deb2 100644 --- a/test/test_suite/errors/try_assign.c3t +++ b/test/test_suite/errors/try_assign.c3t @@ -139,8 +139,8 @@ after_check17: ; preds = %testblock end_block: ; preds = %after_check17, %error %13 = load i64, i64* %e, align 8 - %intbool = icmp ne i64 %13, 0 - br i1 %intbool, label %if.then18, label %if.exit19 + %neq = icmp ne i64 %13, 0 + br i1 %neq, label %if.then18, label %if.exit19 if.then18: ; preds = %end_block %14 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.2, i32 0, i32 0)) diff --git a/test/test_suite/errors/try_catch_if.c3t b/test/test_suite/errors/try_catch_if.c3t index bb844ea59..3d18e1251 100644 --- a/test/test_suite/errors/try_catch_if.c3t +++ b/test/test_suite/errors/try_catch_if.c3t @@ -82,8 +82,8 @@ after.errcheck: ; preds = %testblock1 end_block: ; preds = %after.errcheck, %error3, %error %2 = load i64, i64* %err, align 8 - %intbool = icmp ne i64 %2, 0 - br i1 %intbool, label %if.then, label %if.else + %neq = icmp ne i64 %2, 0 + br i1 %neq, label %if.then, label %if.else if.then: ; preds = %end_block %3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.1, i32 0, i32 0))