From 3d1732ef6c8ebc7edf10485f61b4ec905303cd8a Mon Sep 17 00:00:00 2001 From: Marc Tiehuis Date: Fri, 23 Mar 2018 20:27:11 +1300 Subject: Fix OpqaueType usage in exported c functions We prefer `struct typename`. If a typedef is required, this must be done manually after generation. --- src/codegen.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index a44091bdbf..de8cfa31ed 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -6592,6 +6592,7 @@ static void get_c_type(CodeGen *g, GenH *gen_h, TypeTableEntry *type_entry, Buf } } case TypeTableEntryIdStruct: + case TypeTableEntryIdOpaque: { buf_init_from_str(out_buf, "struct "); buf_append_buf(out_buf, &type_entry->name); @@ -6609,11 +6610,6 @@ static void get_c_type(CodeGen *g, GenH *gen_h, TypeTableEntry *type_entry, Buf buf_append_buf(out_buf, &type_entry->name); return; } - case TypeTableEntryIdOpaque: - { - buf_init_from_buf(out_buf, &type_entry->name); - return; - } case TypeTableEntryIdArray: { TypeTableEntryArray *array_data = &type_entry->data.array; -- cgit v1.2.3 From b1c07c0ea9e351a43c9bc2fe747fc07c0a19e005 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 12 Mar 2018 23:03:47 -0400 Subject: move error ret tracing codegen to zig ir progress towards #821 --- src/all_types.hpp | 5 ++++ src/codegen.cpp | 39 +++++++++++-------------- src/ir.cpp | 86 +++++++++++++++++++++++++++++++++++++++---------------- src/ir_print.cpp | 7 +++++ 4 files changed, 91 insertions(+), 46 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index c1dec80d7e..b5428c9599 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2034,6 +2034,7 @@ enum IrInstructionId { IrInstructionIdAtomicRmw, IrInstructionIdPromiseResultType, IrInstructionIdAwaitBookkeeping, + IrInstructionIdSaveErrRetAddr, }; struct IrInstruction { @@ -2988,6 +2989,10 @@ struct IrInstructionAwaitBookkeeping { IrInstruction *promise_result_type; }; +struct IrInstructionSaveErrRetAddr { + IrInstruction base; +}; + static const size_t slice_ptr_index = 0; static const size_t slice_len_index = 1; diff --git a/src/codegen.cpp b/src/codegen.cpp index de8cfa31ed..eddadb94ea 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1607,32 +1607,25 @@ static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) { return instruction->llvm_value; } +static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *executable, + IrInstructionSaveErrRetAddr *save_err_ret_addr_instruction) +{ + assert(g->have_err_ret_tracing); + + LLVMValueRef return_err_fn = get_return_err_fn(g); + LLVMValueRef args[] = { + g->cur_err_ret_trace_val, + }; + LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, return_err_fn, args, 1, + get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, ""); + LLVMSetTailCall(call_instruction, true); + return call_instruction; +} + static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *return_instruction) { LLVMValueRef value = ir_llvm_value(g, return_instruction->value); TypeTableEntry *return_type = return_instruction->value->value.type; - if (g->have_err_ret_tracing) { - bool is_err_return = false; - if (return_type->id == TypeTableEntryIdErrorUnion) { - if (return_instruction->value->value.special == ConstValSpecialStatic) { - is_err_return = return_instruction->value->value.data.x_err_union.err != nullptr; - } else if (return_instruction->value->value.special == ConstValSpecialRuntime) { - is_err_return = return_instruction->value->value.data.rh_error_union == RuntimeHintErrorUnionError; - // TODO: emit a branch to check if the return value is an error - } - } else if (return_type->id == TypeTableEntryIdErrorSet) { - is_err_return = true; - } - if (is_err_return) { - LLVMValueRef return_err_fn = get_return_err_fn(g); - LLVMValueRef args[] = { - g->cur_err_ret_trace_val, - }; - LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, return_err_fn, args, 1, - get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, ""); - LLVMSetTailCall(call_instruction, true); - } - } if (handle_is_ptr(return_type)) { if (calling_convention_does_first_arg_return(g->cur_fn->type_entry->data.fn.fn_type_id.cc)) { assert(g->cur_ret_ptr); @@ -4400,6 +4393,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_coro_alloc_helper(g, executable, (IrInstructionCoroAllocHelper *)instruction); case IrInstructionIdAtomicRmw: return ir_render_atomic_rmw(g, executable, (IrInstructionAtomicRmw *)instruction); + case IrInstructionIdSaveErrRetAddr: + return ir_render_save_err_ret_addr(g, executable, (IrInstructionSaveErrRetAddr *)instruction); } zig_unreachable(); } diff --git a/src/ir.cpp b/src/ir.cpp index 8f418e2c2f..a78be66dd6 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -713,6 +713,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAwaitBookkeeping return IrInstructionIdAwaitBookkeeping; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionSaveErrRetAddr *) { + return IrInstructionIdSaveErrRetAddr; +} + template static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { T *special_instruction = allocate(1); @@ -2678,6 +2682,11 @@ static IrInstruction *ir_build_await_bookkeeping(IrBuilder *irb, Scope *scope, A return &instruction->base; } +static IrInstruction *ir_build_save_err_ret_addr(IrBuilder *irb, Scope *scope, AstNode *source_node) { + IrInstructionSaveErrRetAddr *instruction = ir_build_instruction(irb, scope, source_node); + return &instruction->base; +} + static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) { results[ReturnKindUnconditional] = 0; results[ReturnKindError] = 0; @@ -2750,16 +2759,16 @@ static ScopeDeferExpr *get_scope_defer_expr(Scope *scope) { return nullptr; } +static bool exec_is_async(IrExecutable *exec) { + FnTableEntry *fn_entry = exec_fn_entry(exec); + return fn_entry != nullptr && fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync; +} + static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *return_value, bool is_generated_code) { - FnTableEntry *fn_entry = exec_fn_entry(irb->exec); - bool is_async = fn_entry != nullptr && fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync; + bool is_async = exec_is_async(irb->exec); if (!is_async) { - //if (irb->codegen->have_err_ret_tracing) { - // IrInstruction *stack_trace_ptr = ir_build_error_return_trace_nonnull(irb, scope, node); - // ir_build_save_err_ret_addr(irb, scope, node, stack_trace_ptr); - //} IrInstruction *return_inst = ir_build_return(irb, scope, node, return_value); return_inst->is_gen = is_generated_code; return return_inst; @@ -2781,21 +2790,33 @@ static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode // the above blocks are rendered by ir_gen after the rest of codegen } -//static void ir_gen_save_err_ret_addr(IrBuilder *irb, Scope *scope, AstNode *node, bool is_async) { -// if (!irb->codegen->have_err_ret_tracing) -// return; -// -// if (is_async) { -// IrInstruction *err_ret_addr_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_err_ret_addr_ptr); -// IrInstruction *return_address_ptr = ir_build_return_address(irb, scope, node); -// IrInstruction *return_address_usize = ir_build_ptr_to_int(irb, scope, node, return_address_ptr); -// ir_build_store_ptr(irb, scope, node, err_ret_addr_ptr, return_address_usize); -// return; -// } -// -// IrInstruction *stack_trace_ptr = ir_build_error_return_trace_nonnull(irb, scope, node); -// ir_build_save_err_ret_addr(irb, scope, node, stack_trace_ptr); -//} +static bool exec_have_err_ret_trace(CodeGen *g, IrExecutable *exec) { + if (!g->have_err_ret_tracing) + return false; + FnTableEntry *fn_entry = exec_fn_entry(exec); + if (fn_entry == nullptr) + return false; + if (exec->is_inline) + return false; + return type_can_fail(fn_entry->type_entry->data.fn.fn_type_id.return_type); +} + +static void ir_gen_save_err_ret_addr(IrBuilder *irb, Scope *scope, AstNode *node) { + if (!exec_have_err_ret_trace(irb->codegen, irb->exec)) + return; + + bool is_async = exec_is_async(irb->exec); + + if (is_async) { + //IrInstruction *err_ret_addr_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_err_ret_addr_ptr); + //IrInstruction *return_address_ptr = ir_build_instr_addr(irb, scope, node); + //IrInstruction *return_address_usize = ir_build_ptr_to_int(irb, scope, node, return_address_ptr); + //ir_build_store_ptr(irb, scope, node, err_ret_addr_ptr, return_address_usize); + return; + } + + ir_build_save_err_ret_addr(irb, scope, node); +} static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) { assert(node->type == NodeTypeReturnExpr); @@ -2856,7 +2877,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, if (have_err_defers) { ir_gen_defers_for_block(irb, scope, outer_scope, true); } - //ir_gen_save_err_ret_addr(irb, scope, node, is_async); + ir_gen_save_err_ret_addr(irb, scope, node); ir_build_br(irb, scope, node, ret_stmt_block, is_comptime); ir_set_cursor_at_end_and_append_block(irb, ok_block); @@ -2895,6 +2916,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, ir_set_cursor_at_end_and_append_block(irb, return_block); ir_gen_defers_for_block(irb, scope, outer_scope, true); IrInstruction *err_val = ir_build_unwrap_err_code(irb, scope, node, err_union_ptr); + ir_gen_save_err_ret_addr(irb, scope, node); ir_gen_async_return(irb, scope, node, err_val, false); ir_set_cursor_at_end_and_append_block(irb, continue_block); @@ -6406,6 +6428,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec return false; if (!instr_is_unreachable(result)) { + // no need for save_err_ret_addr because this cannot return error ir_gen_async_return(irb, scope, result->source_node, result, true); } @@ -11464,13 +11487,17 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi return ira->codegen->builtin_types.entry_void; } +static bool exec_has_err_ret_trace(CodeGen *g, IrExecutable *exec) { + FnTableEntry *fn_entry = exec_fn_entry(exec); + return fn_entry != nullptr && fn_entry->calls_or_awaits_errorable_fn && g->have_err_ret_tracing; +} + static TypeTableEntry *ir_analyze_instruction_error_return_trace(IrAnalyze *ira, IrInstructionErrorReturnTrace *instruction) { - FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec); TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(ira->codegen); TypeTableEntry *nullable_type = get_maybe_type(ira->codegen, ptr_to_stack_trace_type); - if (fn_entry == nullptr || !fn_entry->calls_or_awaits_errorable_fn || !ira->codegen->have_err_ret_tracing) { + if (!exec_has_err_ret_trace(ira->codegen, ira->new_irb.exec)) { ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); out_val->data.x_maybe = nullptr; return nullable_type; @@ -17775,6 +17802,14 @@ static TypeTableEntry *ir_analyze_instruction_await_bookkeeping(IrAnalyze *ira, return out_val->type; } +static TypeTableEntry *ir_analyze_instruction_save_err_ret_addr(IrAnalyze *ira, IrInstructionSaveErrRetAddr *instruction) { + IrInstruction *result = ir_build_save_err_ret_addr(&ira->new_irb, instruction->base.scope, + instruction->base.source_node); + ir_link_new_instruction(result, &instruction->base); + result->value.type = ira->codegen->builtin_types.entry_void; + return result->value.type; +} + static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { switch (instruction->id) { case IrInstructionIdInvalid: @@ -18012,6 +18047,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi return ir_analyze_instruction_promise_result_type(ira, (IrInstructionPromiseResultType *)instruction); case IrInstructionIdAwaitBookkeeping: return ir_analyze_instruction_await_bookkeeping(ira, (IrInstructionAwaitBookkeeping *)instruction); + case IrInstructionIdSaveErrRetAddr: + return ir_analyze_instruction_save_err_ret_addr(ira, (IrInstructionSaveErrRetAddr *)instruction); } zig_unreachable(); } @@ -18137,6 +18174,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdCoroSave: case IrInstructionIdCoroAllocHelper: case IrInstructionIdAwaitBookkeeping: + case IrInstructionIdSaveErrRetAddr: return true; case IrInstructionIdPhi: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 167bd20839..709cb43942 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -1161,6 +1161,10 @@ static void ir_print_await_bookkeeping(IrPrint *irp, IrInstructionAwaitBookkeepi fprintf(irp->f, ")"); } +static void ir_print_save_err_ret_addr(IrPrint *irp, IrInstructionSaveErrRetAddr *instruction) { + fprintf(irp->f, "@saveErrRetAddr()"); +} + static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { ir_print_prefix(irp, instruction); switch (instruction->id) { @@ -1532,6 +1536,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdAwaitBookkeeping: ir_print_await_bookkeeping(irp, (IrInstructionAwaitBookkeeping *)instruction); break; + case IrInstructionIdSaveErrRetAddr: + ir_print_save_err_ret_addr(irp, (IrInstructionSaveErrRetAddr *)instruction); + break; } fprintf(irp->f, "\n"); } -- cgit v1.2.3 From 18af2f9a2764cc340571578d58cb2575faeccdc6 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 24 Mar 2018 18:21:51 -0400 Subject: fix async fns with inferred error sets closes #856 --- src/all_types.hpp | 12 +++++++++++- src/analyze.cpp | 10 +++++----- src/ast_render.cpp | 11 ++++++++++- src/codegen.cpp | 1 + src/ir.cpp | 45 ++++++++++++++++++++++++++++++++++++++++----- src/ir_print.cpp | 13 +++++++++++-- test/cases/coroutines.zig | 11 +++++++++++ 7 files changed, 89 insertions(+), 14 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index b5428c9599..f5afecfbdd 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1251,7 +1251,10 @@ struct FnTableEntry { ScopeBlock *def_scope; // parent is child_scope Buf symbol_name; TypeTableEntry *type_entry; // function type - TypeTableEntry *implicit_return_type; + // in the case of normal functions this is the implicit return type + // in the case of async functions this is the implicit return type according to the + // zig source code, not according to zig ir + TypeTableEntry *src_implicit_return_type; bool is_test; FnInline fn_inline; FnAnalState anal_state; @@ -2035,6 +2038,7 @@ enum IrInstructionId { IrInstructionIdPromiseResultType, IrInstructionIdAwaitBookkeeping, IrInstructionIdSaveErrRetAddr, + IrInstructionIdAddImplicitReturnType, }; struct IrInstruction { @@ -2993,6 +2997,12 @@ struct IrInstructionSaveErrRetAddr { IrInstruction base; }; +struct IrInstructionAddImplicitReturnType { + IrInstruction base; + + IrInstruction *value; +}; + static const size_t slice_ptr_index = 0; static const size_t slice_len_index = 1; diff --git a/src/analyze.cpp b/src/analyze.cpp index eb1850c8e1..5f2162b2cc 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -3865,7 +3865,7 @@ void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_typ TypeTableEntry *block_return_type = ir_analyze(g, &fn_table_entry->ir_executable, &fn_table_entry->analyzed_executable, fn_type_id->return_type, return_type_node); - fn_table_entry->implicit_return_type = block_return_type; + fn_table_entry->src_implicit_return_type = block_return_type; if (type_is_invalid(block_return_type) || fn_table_entry->analyzed_executable.invalid) { assert(g->errors.length > 0); @@ -3877,10 +3877,10 @@ void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_typ TypeTableEntry *return_err_set_type = fn_type_id->return_type->data.error_union.err_set_type; if (return_err_set_type->data.error_set.infer_fn != nullptr) { TypeTableEntry *inferred_err_set_type; - if (fn_table_entry->implicit_return_type->id == TypeTableEntryIdErrorSet) { - inferred_err_set_type = fn_table_entry->implicit_return_type; - } else if (fn_table_entry->implicit_return_type->id == TypeTableEntryIdErrorUnion) { - inferred_err_set_type = fn_table_entry->implicit_return_type->data.error_union.err_set_type; + if (fn_table_entry->src_implicit_return_type->id == TypeTableEntryIdErrorSet) { + inferred_err_set_type = fn_table_entry->src_implicit_return_type; + } else if (fn_table_entry->src_implicit_return_type->id == TypeTableEntryIdErrorUnion) { + inferred_err_set_type = fn_table_entry->src_implicit_return_type->data.error_union.err_set_type; } else { add_node_error(g, return_type_node, buf_sprintf("function with inferred error set must return at least one possible error")); diff --git a/src/ast_render.cpp b/src/ast_render.cpp index f88feee856..432489c4d9 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -658,6 +658,15 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { if (node->data.fn_call_expr.is_builtin) { fprintf(ar->f, "@"); } + if (node->data.fn_call_expr.is_async) { + fprintf(ar->f, "async"); + if (node->data.fn_call_expr.async_allocator != nullptr) { + fprintf(ar->f, "<"); + render_node_extra(ar, node->data.fn_call_expr.async_allocator, true); + fprintf(ar->f, ">"); + } + fprintf(ar->f, " "); + } AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr; bool grouped = (fn_ref_node->type != NodeTypePrefixOpExpr && fn_ref_node->type != NodeTypeAddrOfExpr); render_node_extra(ar, fn_ref_node, grouped); @@ -1023,7 +1032,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { case NodeTypeUnwrapErrorExpr: { render_node_ungrouped(ar, node->data.unwrap_err_expr.op1); - fprintf(ar->f, " %%%% "); + fprintf(ar->f, " catch "); if (node->data.unwrap_err_expr.symbol) { Buf *var_name = node->data.unwrap_err_expr.symbol->data.symbol_expr.symbol; fprintf(ar->f, "|%s| ", buf_ptr(var_name)); diff --git a/src/codegen.cpp b/src/codegen.cpp index eddadb94ea..d675010531 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -4245,6 +4245,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdErrorUnion: case IrInstructionIdPromiseResultType: case IrInstructionIdAwaitBookkeeping: + case IrInstructionIdAddImplicitReturnType: zig_unreachable(); case IrInstructionIdReturn: diff --git a/src/ir.cpp b/src/ir.cpp index a78be66dd6..d896153d0b 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -34,7 +34,7 @@ struct IrAnalyze { size_t old_bb_index; size_t instruction_index; TypeTableEntry *explicit_return_type; - ZigList implicit_return_type_list; + ZigList src_implicit_return_type_list; IrBasicBlock *const_predecessor_bb; }; @@ -717,6 +717,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSaveErrRetAddr * return IrInstructionIdSaveErrRetAddr; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionAddImplicitReturnType *) { + return IrInstructionIdAddImplicitReturnType; +} + template static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { T *special_instruction = allocate(1); @@ -2687,6 +2691,17 @@ static IrInstruction *ir_build_save_err_ret_addr(IrBuilder *irb, Scope *scope, A return &instruction->base; } +static IrInstruction *ir_build_add_implicit_return_type(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *value) +{ + IrInstructionAddImplicitReturnType *instruction = ir_build_instruction(irb, scope, source_node); + instruction->value = value; + + ir_ref_instruction(value, irb->current_basic_block); + + return &instruction->base; +} + static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) { results[ReturnKindUnconditional] = 0; results[ReturnKindError] = 0; @@ -2767,6 +2782,8 @@ static bool exec_is_async(IrExecutable *exec) { static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *return_value, bool is_generated_code) { + ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, node, return_value)); + bool is_async = exec_is_async(irb->exec); if (!is_async) { IrInstruction *return_inst = ir_build_return(irb, scope, node, return_value); @@ -6399,6 +6416,8 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec ir_build_cond_br(irb, scope, node, alloc_result_is_ok, alloc_ok_block, alloc_err_block, const_bool_false); ir_set_cursor_at_end_and_append_block(irb, alloc_err_block); + // we can return undefined here, because the caller passes a pointer to the error struct field + // in the error union result, and we populate it in case of allocation failure. IrInstruction *undef = ir_build_const_undefined(irb, scope, node); ir_build_return(irb, scope, node, undef); @@ -10108,13 +10127,26 @@ static Buf *ir_resolve_str(IrAnalyze *ira, IrInstruction *value) { return result; } +static TypeTableEntry *ir_analyze_instruction_add_implicit_return_type(IrAnalyze *ira, + IrInstructionAddImplicitReturnType *instruction) +{ + IrInstruction *value = instruction->value->other; + if (type_is_invalid(value->value.type)) + return ir_unreach_error(ira); + + ira->src_implicit_return_type_list.append(value); + + ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); + out_val->type = ira->codegen->builtin_types.entry_void; + return out_val->type; +} + static TypeTableEntry *ir_analyze_instruction_return(IrAnalyze *ira, IrInstructionReturn *return_instruction) { IrInstruction *value = return_instruction->value->other; if (type_is_invalid(value->value.type)) return ir_unreach_error(ira); - ira->implicit_return_type_list.append(value); IrInstruction *casted_value = ir_implicit_cast(ira, value, ira->explicit_return_type); if (casted_value == ira->codegen->invalid_instruction) @@ -18049,6 +18081,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi return ir_analyze_instruction_await_bookkeeping(ira, (IrInstructionAwaitBookkeeping *)instruction); case IrInstructionIdSaveErrRetAddr: return ir_analyze_instruction_save_err_ret_addr(ira, (IrInstructionSaveErrRetAddr *)instruction); + case IrInstructionIdAddImplicitReturnType: + return ir_analyze_instruction_add_implicit_return_type(ira, (IrInstructionAddImplicitReturnType *)instruction); } zig_unreachable(); } @@ -18122,11 +18156,11 @@ TypeTableEntry *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutabl if (new_exec->invalid) { return ira->codegen->builtin_types.entry_invalid; - } else if (ira->implicit_return_type_list.length == 0) { + } else if (ira->src_implicit_return_type_list.length == 0) { return codegen->builtin_types.entry_unreachable; } else { - return ir_resolve_peer_types(ira, expected_type_source_node, ira->implicit_return_type_list.items, - ira->implicit_return_type_list.length); + return ir_resolve_peer_types(ira, expected_type_source_node, ira->src_implicit_return_type_list.items, + ira->src_implicit_return_type_list.length); } } @@ -18175,6 +18209,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdCoroAllocHelper: case IrInstructionIdAwaitBookkeeping: case IrInstructionIdSaveErrRetAddr: + case IrInstructionIdAddImplicitReturnType: return true; case IrInstructionIdPhi: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 709cb43942..5008d3564d 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -201,9 +201,9 @@ static void ir_print_call(IrPrint *irp, IrInstructionCall *call_instruction) { if (call_instruction->is_async) { fprintf(irp->f, "async"); if (call_instruction->async_allocator != nullptr) { - fprintf(irp->f, "("); + fprintf(irp->f, "<"); ir_print_other_instruction(irp, call_instruction->async_allocator); - fprintf(irp->f, ")"); + fprintf(irp->f, ">"); } fprintf(irp->f, " "); } @@ -1165,6 +1165,12 @@ static void ir_print_save_err_ret_addr(IrPrint *irp, IrInstructionSaveErrRetAddr fprintf(irp->f, "@saveErrRetAddr()"); } +static void ir_print_add_implicit_return_type(IrPrint *irp, IrInstructionAddImplicitReturnType *instruction) { + fprintf(irp->f, "@addImplicitReturnType("); + ir_print_other_instruction(irp, instruction->value); + fprintf(irp->f, ")"); +} + static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { ir_print_prefix(irp, instruction); switch (instruction->id) { @@ -1539,6 +1545,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdSaveErrRetAddr: ir_print_save_err_ret_addr(irp, (IrInstructionSaveErrRetAddr *)instruction); break; + case IrInstructionIdAddImplicitReturnType: + ir_print_add_implicit_return_type(irp, (IrInstructionAddImplicitReturnType *)instruction); + break; } fprintf(irp->f, "\n"); } diff --git a/test/cases/coroutines.zig b/test/cases/coroutines.zig index f8ad58f70d..087d561713 100644 --- a/test/cases/coroutines.zig +++ b/test/cases/coroutines.zig @@ -176,3 +176,14 @@ async<&std.mem.Allocator> fn simpleAsyncFn2(y: &i32) void { *y += 1; suspend; } + +test "async fn with inferred error set" { + const p = (async failing()) catch unreachable; + resume p; + cancel p; +} + +async fn failing() !void { + suspend; + return error.Fail; +} -- cgit v1.2.3 From 897e783763d60449ad1b9514cb5ba86a38f7ae4a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 24 Mar 2018 19:25:53 -0400 Subject: add promise->T syntax parsing closes #857 --- doc/langref.html.in | 4 +++- src/all_types.hpp | 13 ++++++++++++ src/analyze.cpp | 1 + src/ast_render.cpp | 11 ++++++++++ src/codegen.cpp | 1 + src/ir.cpp | 54 +++++++++++++++++++++++++++++++++++++++++++++++ src/ir_print.cpp | 11 ++++++++++ src/parser.cpp | 14 +++++++++++- src/tokenizer.cpp | 2 ++ src/tokenizer.hpp | 1 + test/cases/coroutines.zig | 1 + 11 files changed, 111 insertions(+), 2 deletions(-) (limited to 'src/codegen.cpp') diff --git a/doc/langref.html.in b/doc/langref.html.in index f4aa42eb89..b2e14ac195 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -5863,7 +5863,9 @@ StructLiteralField = "." Symbol "=" Expression PrefixOp = "!" | "-" | "~" | "*" | ("&" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try" | "await" -PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ContainerDecl | ("continue" option(":" Symbol)) | ErrorSetDecl +PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ContainerDecl | ("continue" option(":" Symbol)) | ErrorSetDecl | PromiseType + +PromiseType = "promise" option("->" TypeExpr) ArrayType : "[" option(Expression) "]" option("align" "(" Expression option(":" Integer ":" Integer) ")")) option("const") option("volatile") TypeExpr diff --git a/src/all_types.hpp b/src/all_types.hpp index f5afecfbdd..64b9b31662 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -409,6 +409,7 @@ enum NodeType { NodeTypeResume, NodeTypeAwaitExpr, NodeTypeSuspend, + NodeTypePromiseType, }; struct AstNodeRoot { @@ -879,6 +880,10 @@ struct AstNodeSuspend { AstNode *promise_symbol; }; +struct AstNodePromiseType { + AstNode *payload_type; // can be NULL +}; + struct AstNode { enum NodeType type; size_t line; @@ -939,6 +944,7 @@ struct AstNode { AstNodeResumeExpr resume_expr; AstNodeAwaitExpr await_expr; AstNodeSuspend suspend; + AstNodePromiseType promise_type; } data; }; @@ -1947,6 +1953,7 @@ enum IrInstructionId { IrInstructionIdSetRuntimeSafety, IrInstructionIdSetFloatMode, IrInstructionIdArrayType, + IrInstructionIdPromiseType, IrInstructionIdSliceType, IrInstructionIdAsm, IrInstructionIdSizeOf, @@ -2365,6 +2372,12 @@ struct IrInstructionArrayType { IrInstruction *child_type; }; +struct IrInstructionPromiseType { + IrInstruction base; + + IrInstruction *payload_type; +}; + struct IrInstructionSliceType { IrInstruction base; diff --git a/src/analyze.cpp b/src/analyze.cpp index 5f2162b2cc..0f4728f822 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -3254,6 +3254,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) { case NodeTypeResume: case NodeTypeAwaitExpr: case NodeTypeSuspend: + case NodeTypePromiseType: zig_unreachable(); } } diff --git a/src/ast_render.cpp b/src/ast_render.cpp index 432489c4d9..7b5fc03ea8 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -250,6 +250,8 @@ static const char *node_type_str(NodeType node_type) { return "AwaitExpr"; case NodeTypeSuspend: return "Suspend"; + case NodeTypePromiseType: + return "PromiseType"; } zig_unreachable(); } @@ -781,6 +783,15 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { render_node_ungrouped(ar, node->data.array_type.child_type); break; } + case NodeTypePromiseType: + { + fprintf(ar->f, "promise"); + if (node->data.promise_type.payload_type != nullptr) { + fprintf(ar->f, "->"); + render_node_grouped(ar, node->data.promise_type.payload_type); + } + break; + } case NodeTypeErrorType: fprintf(ar->f, "error"); break; diff --git a/src/codegen.cpp b/src/codegen.cpp index d675010531..786bd03985 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -4205,6 +4205,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdSetRuntimeSafety: case IrInstructionIdSetFloatMode: case IrInstructionIdArrayType: + case IrInstructionIdPromiseType: case IrInstructionIdSliceType: case IrInstructionIdSizeOf: case IrInstructionIdSwitchTarget: diff --git a/src/ir.cpp b/src/ir.cpp index d896153d0b..95142c88de 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -349,6 +349,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionArrayType *) { return IrInstructionIdArrayType; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionPromiseType *) { + return IrInstructionIdPromiseType; +} + static constexpr IrInstructionId ir_instruction_id(IrInstructionSliceType *) { return IrInstructionIdSliceType; } @@ -1469,6 +1473,17 @@ static IrInstruction *ir_build_array_type(IrBuilder *irb, Scope *scope, AstNode return &instruction->base; } +static IrInstruction *ir_build_promise_type(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *payload_type) +{ + IrInstructionPromiseType *instruction = ir_build_instruction(irb, scope, source_node); + instruction->payload_type = payload_type; + + if (payload_type != nullptr) ir_ref_instruction(payload_type, irb->current_basic_block); + + return &instruction->base; +} + static IrInstruction *ir_build_slice_type(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *child_type, bool is_const, bool is_volatile, IrInstruction *align_value) { @@ -5074,6 +5089,22 @@ static IrInstruction *ir_gen_array_type(IrBuilder *irb, Scope *scope, AstNode *n } } +static IrInstruction *ir_gen_promise_type(IrBuilder *irb, Scope *scope, AstNode *node) { + assert(node->type == NodeTypePromiseType); + + AstNode *payload_type_node = node->data.promise_type.payload_type; + IrInstruction *payload_type_value = nullptr; + + if (payload_type_node != nullptr) { + payload_type_value = ir_gen_node(irb, payload_type_node, scope); + if (payload_type_value == irb->codegen->invalid_instruction) + return payload_type_value; + + } + + return ir_build_promise_type(irb, scope, node, payload_type_value); +} + static IrInstruction *ir_gen_undefined_literal(IrBuilder *irb, Scope *scope, AstNode *node) { assert(node->type == NodeTypeUndefinedLiteral); return ir_build_const_undefined(irb, scope, node); @@ -6282,6 +6313,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop return ir_lval_wrap(irb, scope, ir_gen_bool_literal(irb, scope, node), lval); case NodeTypeArrayType: return ir_lval_wrap(irb, scope, ir_gen_array_type(irb, scope, node), lval); + case NodeTypePromiseType: + return ir_lval_wrap(irb, scope, ir_gen_promise_type(irb, scope, node), lval); case NodeTypeStringLiteral: return ir_lval_wrap(irb, scope, ir_gen_string_literal(irb, scope, node), lval); case NodeTypeUndefinedLiteral: @@ -14069,6 +14102,24 @@ static TypeTableEntry *ir_analyze_instruction_array_type(IrAnalyze *ira, zig_unreachable(); } +static TypeTableEntry *ir_analyze_instruction_promise_type(IrAnalyze *ira, IrInstructionPromiseType *instruction) { + TypeTableEntry *promise_type; + + if (instruction->payload_type == nullptr) { + promise_type = ira->codegen->builtin_types.entry_promise; + } else { + TypeTableEntry *payload_type = ir_resolve_type(ira, instruction->payload_type->other); + if (type_is_invalid(payload_type)) + return ira->codegen->builtin_types.entry_invalid; + + promise_type = get_promise_type(ira->codegen, payload_type); + } + + ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); + out_val->data.x_type = promise_type; + return ira->codegen->builtin_types.entry_type; +} + static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira, IrInstructionSizeOf *size_of_instruction) { @@ -17907,6 +17958,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi return ir_analyze_instruction_asm(ira, (IrInstructionAsm *)instruction); case IrInstructionIdArrayType: return ir_analyze_instruction_array_type(ira, (IrInstructionArrayType *)instruction); + case IrInstructionIdPromiseType: + return ir_analyze_instruction_promise_type(ira, (IrInstructionPromiseType *)instruction); case IrInstructionIdSizeOf: return ir_analyze_instruction_size_of(ira, (IrInstructionSizeOf *)instruction); case IrInstructionIdTestNonNull: @@ -18232,6 +18285,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdStructFieldPtr: case IrInstructionIdUnionFieldPtr: case IrInstructionIdArrayType: + case IrInstructionIdPromiseType: case IrInstructionIdSliceType: case IrInstructionIdSizeOf: case IrInstructionIdTestNonNull: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 5008d3564d..b14d49a4ca 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -404,6 +404,14 @@ static void ir_print_array_type(IrPrint *irp, IrInstructionArrayType *instructio ir_print_other_instruction(irp, instruction->child_type); } +static void ir_print_promise_type(IrPrint *irp, IrInstructionPromiseType *instruction) { + fprintf(irp->f, "promise"); + if (instruction->payload_type != nullptr) { + fprintf(irp->f, "->"); + ir_print_other_instruction(irp, instruction->payload_type); + } +} + static void ir_print_slice_type(IrPrint *irp, IrInstructionSliceType *instruction) { const char *const_kw = instruction->is_const ? "const " : ""; fprintf(irp->f, "[]%s", const_kw); @@ -1263,6 +1271,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdArrayType: ir_print_array_type(irp, (IrInstructionArrayType *)instruction); break; + case IrInstructionIdPromiseType: + ir_print_promise_type(irp, (IrInstructionPromiseType *)instruction); + break; case IrInstructionIdSliceType: ir_print_slice_type(irp, (IrInstructionSliceType *)instruction); break; diff --git a/src/parser.cpp b/src/parser.cpp index 666b9da3c3..d6faf4c984 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -705,7 +705,7 @@ static AstNode *ast_parse_comptime_expr(ParseContext *pc, size_t *token_index, b } /* -PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ContainerDecl | ("continue" option(":" Symbol)) | ErrorSetDecl +PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ContainerDecl | ("continue" option(":" Symbol)) | ErrorSetDecl | PromiseType KeywordLiteral = "true" | "false" | "null" | "undefined" | "error" | "this" | "unreachable" | "suspend" ErrorSetDecl = "error" "{" list(Symbol, ",") "}" */ @@ -774,6 +774,15 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo AstNode *node = ast_create_node(pc, NodeTypeSuspend, token); *token_index += 1; return node; + } else if (token->id == TokenIdKeywordPromise) { + AstNode *node = ast_create_node(pc, NodeTypePromiseType, token); + *token_index += 1; + Token *arrow_tok = &pc->tokens->at(*token_index); + if (arrow_tok->id == TokenIdArrow) { + *token_index += 1; + node->data.promise_type.payload_type = ast_parse_type_expr(pc, token_index, true); + } + return node; } else if (token->id == TokenIdKeywordError) { Token *next_token = &pc->tokens->at(*token_index + 1); if (next_token->id == TokenIdLBrace) { @@ -3081,6 +3090,9 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont visit_field(&node->data.array_type.child_type, visit, context); visit_field(&node->data.array_type.align_expr, visit, context); break; + case NodeTypePromiseType: + visit_field(&node->data.promise_type.payload_type, visit, context); + break; case NodeTypeErrorType: // none break; diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index dc17829c0f..365b35cdfd 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -135,6 +135,7 @@ static const struct ZigKeyword zig_keywords[] = { {"null", TokenIdKeywordNull}, {"or", TokenIdKeywordOr}, {"packed", TokenIdKeywordPacked}, + {"promise", TokenIdKeywordPromise}, {"pub", TokenIdKeywordPub}, {"resume", TokenIdKeywordResume}, {"return", TokenIdKeywordReturn}, @@ -1558,6 +1559,7 @@ const char * token_name(TokenId id) { case TokenIdKeywordNull: return "null"; case TokenIdKeywordOr: return "or"; case TokenIdKeywordPacked: return "packed"; + case TokenIdKeywordPromise: return "promise"; case TokenIdKeywordPub: return "pub"; case TokenIdKeywordReturn: return "return"; case TokenIdKeywordSection: return "section"; diff --git a/src/tokenizer.hpp b/src/tokenizer.hpp index 2d71427997..b719293704 100644 --- a/src/tokenizer.hpp +++ b/src/tokenizer.hpp @@ -76,6 +76,7 @@ enum TokenId { TokenIdKeywordNull, TokenIdKeywordOr, TokenIdKeywordPacked, + TokenIdKeywordPromise, TokenIdKeywordPub, TokenIdKeywordResume, TokenIdKeywordReturn, diff --git a/test/cases/coroutines.zig b/test/cases/coroutines.zig index 087d561713..25a75dca5c 100644 --- a/test/cases/coroutines.zig +++ b/test/cases/coroutines.zig @@ -5,6 +5,7 @@ var x: i32 = 1; test "create a coroutine and cancel it" { const p = try async simpleAsyncFn(); + comptime assert(@typeOf(p) == promise->void); cancel p; assert(x == 2); } -- cgit v1.2.3 From aa2995ee395b2c1329a61513debcac6225fcb8a8 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 24 Mar 2018 22:05:29 -0400 Subject: fix invalid codegen for error return traces across suspend points See #821 Now the code works correctly, but error return traces are missing the frames from coroutines. --- src/all_types.hpp | 10 ++++++- src/analyze.cpp | 7 +++++ src/analyze.hpp | 1 + src/codegen.cpp | 65 +++++++++++++++++++++++++++++++++++----------- src/ir.cpp | 69 +++++++++++++++++++++++++------------------------ test/runtime_safety.zig | 30 +++++++++++++++++++++ 6 files changed, 132 insertions(+), 50 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index 64b9b31662..6951230aa4 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1621,7 +1621,8 @@ struct CodeGen { FnTableEntry *panic_fn; LLVMValueRef cur_ret_ptr; LLVMValueRef cur_fn_val; - LLVMValueRef cur_err_ret_trace_val; + LLVMValueRef cur_err_ret_trace_val_arg; + LLVMValueRef cur_err_ret_trace_val_stack; bool c_want_stdint; bool c_want_stdbool; AstNode *root_export_decl; @@ -1760,6 +1761,7 @@ enum ScopeId { ScopeIdLoop, ScopeIdFnDef, ScopeIdCompTime, + ScopeIdCoroPrelude, }; struct Scope { @@ -1867,6 +1869,12 @@ struct ScopeFnDef { FnTableEntry *fn_entry; }; +// This scope is created to indicate that the code in the scope +// is auto-generated coroutine prelude stuff. +struct ScopeCoroPrelude { + Scope base; +}; + // synchronized with code in define_builtin_compile_vars enum AtomicOrder { AtomicOrderUnordered, diff --git a/src/analyze.cpp b/src/analyze.cpp index 0f4728f822..7ee1de78a2 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -170,6 +170,12 @@ Scope *create_comptime_scope(AstNode *node, Scope *parent) { return &scope->base; } +Scope *create_coro_prelude_scope(AstNode *node, Scope *parent) { + ScopeCoroPrelude *scope = allocate(1); + init_scope(&scope->base, ScopeIdCoroPrelude, node, parent); + return &scope->base; +} + ImportTableEntry *get_scope_import(Scope *scope) { while (scope) { if (scope->id == ScopeIdDecls) { @@ -3592,6 +3598,7 @@ FnTableEntry *scope_get_fn_if_root(Scope *scope) { case ScopeIdCImport: case ScopeIdLoop: case ScopeIdCompTime: + case ScopeIdCoroPrelude: scope = scope->parent; continue; case ScopeIdFnDef: diff --git a/src/analyze.hpp b/src/analyze.hpp index 936134030d..aa4557666b 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -107,6 +107,7 @@ ScopeLoop *create_loop_scope(AstNode *node, Scope *parent); ScopeFnDef *create_fndef_scope(AstNode *node, Scope *parent, FnTableEntry *fn_entry); ScopeDecls *create_decls_scope(AstNode *node, Scope *parent, TypeTableEntry *container_type, ImportTableEntry *import); Scope *create_comptime_scope(AstNode *node, Scope *parent); +Scope *create_coro_prelude_scope(AstNode *node, Scope *parent); void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str); ConstExprValue *create_const_str_lit(CodeGen *g, Buf *str); diff --git a/src/codegen.cpp b/src/codegen.cpp index 786bd03985..25b2ffbf16 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -653,6 +653,7 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) { case ScopeIdDeferExpr: case ScopeIdLoop: case ScopeIdCompTime: + case ScopeIdCoroPrelude: return get_di_scope(g, scope->parent); } zig_unreachable(); @@ -1318,9 +1319,34 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) { return fn_val; } -static void gen_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val) { +static bool is_coro_prelude_scope(Scope *scope) { + while (scope != nullptr) { + if (scope->id == ScopeIdCoroPrelude) { + return true; + } else if (scope->id == ScopeIdFnDef) { + break; + } + scope = scope->parent; + } + return false; +} + +static LLVMValueRef get_cur_err_ret_trace_val(CodeGen *g, Scope *scope) { + if (!g->have_err_ret_tracing) { + return nullptr; + } + if (g->cur_fn->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync) { + return is_coro_prelude_scope(scope) ? g->cur_err_ret_trace_val_arg : g->cur_err_ret_trace_val_stack; + } + if (g->cur_err_ret_trace_val_stack != nullptr) { + return g->cur_err_ret_trace_val_stack; + } + return g->cur_err_ret_trace_val_arg; +} + +static void gen_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val, Scope *scope) { LLVMValueRef safety_crash_err_fn = get_safety_crash_err_fn(g); - LLVMValueRef err_ret_trace_val = g->cur_err_ret_trace_val; + LLVMValueRef err_ret_trace_val = get_cur_err_ret_trace_val(g, scope); if (err_ret_trace_val == nullptr) { TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g); err_ret_trace_val = LLVMConstNull(ptr_to_stack_trace_type->type_ref); @@ -1614,7 +1640,7 @@ static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *execut LLVMValueRef return_err_fn = get_return_err_fn(g); LLVMValueRef args[] = { - g->cur_err_ret_trace_val, + get_cur_err_ret_trace_val(g, save_err_ret_addr_instruction->base.scope), }; LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, return_err_fn, args, 1, get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, ""); @@ -2725,7 +2751,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr gen_param_index += 1; } if (prefix_arg_err_ret_stack) { - gen_param_values[gen_param_index] = g->cur_err_ret_trace_val; + gen_param_values[gen_param_index] = get_cur_err_ret_trace_val(g, instruction->base.scope); gen_param_index += 1; } if (instruction->is_async) { @@ -3292,11 +3318,12 @@ static LLVMValueRef ir_render_align_cast(CodeGen *g, IrExecutable *executable, I static LLVMValueRef ir_render_error_return_trace(CodeGen *g, IrExecutable *executable, IrInstructionErrorReturnTrace *instruction) { - if (g->cur_err_ret_trace_val == nullptr) { + LLVMValueRef cur_err_ret_trace_val = get_cur_err_ret_trace_val(g, instruction->base.scope); + if (cur_err_ret_trace_val == nullptr) { TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g); return LLVMConstNull(ptr_to_stack_trace_type->type_ref); } - return g->cur_err_ret_trace_val; + return cur_err_ret_trace_val; } static LLVMValueRef ir_render_cancel(CodeGen *g, IrExecutable *executable, IrInstructionCancel *instruction) { @@ -3726,7 +3753,7 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu LLVMBuildCondBr(g->builder, cond_val, ok_block, err_block); LLVMPositionBuilderAtEnd(g->builder, err_block); - gen_safety_crash_for_err(g, err_val); + gen_safety_crash_for_err(g, err_val, instruction->base.scope); LLVMPositionBuilderAtEnd(g->builder, ok_block); } @@ -3918,7 +3945,7 @@ static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *exec } static LLVMValueRef ir_render_panic(CodeGen *g, IrExecutable *executable, IrInstructionPanic *instruction) { - gen_panic(g, ir_llvm_value(g, instruction->msg), g->cur_err_ret_trace_val); + gen_panic(g, ir_llvm_value(g, instruction->msg), get_cur_err_ret_trace_val(g, instruction->base.scope)); return nullptr; } @@ -5279,9 +5306,17 @@ static void do_code_gen(CodeGen *g) { clear_debug_source_node(g); uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry); - if (err_ret_trace_arg_index != UINT32_MAX) { - g->cur_err_ret_trace_val = LLVMGetParam(fn, err_ret_trace_arg_index); - } else if (g->have_err_ret_tracing && fn_table_entry->calls_or_awaits_errorable_fn) { + bool have_err_ret_trace_arg = err_ret_trace_arg_index != UINT32_MAX; + if (have_err_ret_trace_arg) { + g->cur_err_ret_trace_val_arg = LLVMGetParam(fn, err_ret_trace_arg_index); + } else { + g->cur_err_ret_trace_val_arg = nullptr; + } + + bool is_async = fn_table_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync; + bool have_err_ret_trace_stack = g->have_err_ret_tracing && fn_table_entry->calls_or_awaits_errorable_fn && + (is_async || !have_err_ret_trace_arg); + if (have_err_ret_trace_stack) { // TODO call graph analysis to find out what this number needs to be for every function static const size_t stack_trace_ptr_count = 30; @@ -5289,13 +5324,13 @@ static void do_code_gen(CodeGen *g) { TypeTableEntry *array_type = get_array_type(g, usize, stack_trace_ptr_count); LLVMValueRef err_ret_array_val = build_alloca(g, array_type, "error_return_trace_addresses", get_abi_alignment(g, array_type)); - g->cur_err_ret_trace_val = build_alloca(g, g->stack_trace_type, "error_return_trace", get_abi_alignment(g, g->stack_trace_type)); + g->cur_err_ret_trace_val_stack = build_alloca(g, g->stack_trace_type, "error_return_trace", get_abi_alignment(g, g->stack_trace_type)); size_t index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index; - LLVMValueRef index_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val, (unsigned)index_field_index, ""); + LLVMValueRef index_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val_stack, (unsigned)index_field_index, ""); gen_store_untyped(g, LLVMConstNull(usize->type_ref), index_field_ptr, 0, false); size_t addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index; - LLVMValueRef addresses_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val, (unsigned)addresses_field_index, ""); + LLVMValueRef addresses_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val_stack, (unsigned)addresses_field_index, ""); TypeTableEntry *slice_type = g->stack_trace_type->data.structure.fields[1].type_entry; size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index].gen_index; @@ -5311,7 +5346,7 @@ static void do_code_gen(CodeGen *g) { LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, addresses_field_ptr, (unsigned)len_field_index, ""); gen_store(g, LLVMConstInt(usize->type_ref, stack_trace_ptr_count, false), len_field_ptr, get_pointer_to_type(g, usize, false)); } else { - g->cur_err_ret_trace_val = nullptr; + g->cur_err_ret_trace_val_stack = nullptr; } // allocate temporary stack data diff --git a/src/ir.cpp b/src/ir.cpp index 95142c88de..d86b7f5b21 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -6412,60 +6412,61 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec VariableTableEntry *coro_size_var; if (is_async) { // create the coro promise - const_bool_false = ir_build_const_bool(irb, scope, node, false); - VariableTableEntry *promise_var = ir_create_var(irb, node, scope, nullptr, false, false, true, const_bool_false); + Scope *coro_scope = create_coro_prelude_scope(node, scope); + const_bool_false = ir_build_const_bool(irb, coro_scope, node, false); + VariableTableEntry *promise_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false); return_type = fn_entry->type_entry->data.fn.fn_type_id.return_type; - IrInstruction *promise_init = ir_build_const_promise_init(irb, scope, node, return_type); - ir_build_var_decl(irb, scope, node, promise_var, nullptr, nullptr, promise_init); - IrInstruction *coro_promise_ptr = ir_build_var_ptr(irb, scope, node, promise_var, false, false); + IrInstruction *promise_init = ir_build_const_promise_init(irb, coro_scope, node, return_type); + ir_build_var_decl(irb, coro_scope, node, promise_var, nullptr, nullptr, promise_init); + IrInstruction *coro_promise_ptr = ir_build_var_ptr(irb, coro_scope, node, promise_var, false, false); - VariableTableEntry *await_handle_var = ir_create_var(irb, node, scope, nullptr, false, false, true, const_bool_false); - IrInstruction *null_value = ir_build_const_null(irb, scope, node); - IrInstruction *await_handle_type_val = ir_build_const_type(irb, scope, node, + VariableTableEntry *await_handle_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false); + IrInstruction *null_value = ir_build_const_null(irb, coro_scope, node); + IrInstruction *await_handle_type_val = ir_build_const_type(irb, coro_scope, node, get_maybe_type(irb->codegen, irb->codegen->builtin_types.entry_promise)); - ir_build_var_decl(irb, scope, node, await_handle_var, await_handle_type_val, nullptr, null_value); - irb->exec->await_handle_var_ptr = ir_build_var_ptr(irb, scope, node, + ir_build_var_decl(irb, coro_scope, node, await_handle_var, await_handle_type_val, nullptr, null_value); + irb->exec->await_handle_var_ptr = ir_build_var_ptr(irb, coro_scope, node, await_handle_var, false, false); - u8_ptr_type = ir_build_const_type(irb, scope, node, + u8_ptr_type = ir_build_const_type(irb, coro_scope, node, get_pointer_to_type(irb->codegen, irb->codegen->builtin_types.entry_u8, false)); - IrInstruction *promise_as_u8_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type, coro_promise_ptr); - coro_id = ir_build_coro_id(irb, scope, node, promise_as_u8_ptr); - coro_size_var = ir_create_var(irb, node, scope, nullptr, false, false, true, const_bool_false); - IrInstruction *coro_size = ir_build_coro_size(irb, scope, node); - ir_build_var_decl(irb, scope, node, coro_size_var, nullptr, nullptr, coro_size); - IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, scope, node, + IrInstruction *promise_as_u8_ptr = ir_build_ptr_cast(irb, coro_scope, node, u8_ptr_type, coro_promise_ptr); + coro_id = ir_build_coro_id(irb, coro_scope, node, promise_as_u8_ptr); + coro_size_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false); + IrInstruction *coro_size = ir_build_coro_size(irb, coro_scope, node); + ir_build_var_decl(irb, coro_scope, node, coro_size_var, nullptr, nullptr, coro_size); + IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, coro_scope, node, ImplicitAllocatorIdArg); - irb->exec->coro_allocator_var = ir_create_var(irb, node, scope, nullptr, true, true, true, const_bool_false); - ir_build_var_decl(irb, scope, node, irb->exec->coro_allocator_var, nullptr, nullptr, implicit_allocator_ptr); + irb->exec->coro_allocator_var = ir_create_var(irb, node, coro_scope, nullptr, true, true, true, const_bool_false); + ir_build_var_decl(irb, coro_scope, node, irb->exec->coro_allocator_var, nullptr, nullptr, implicit_allocator_ptr); Buf *alloc_field_name = buf_create_from_str(ASYNC_ALLOC_FIELD_NAME); - IrInstruction *alloc_fn_ptr = ir_build_field_ptr(irb, scope, node, implicit_allocator_ptr, alloc_field_name); - IrInstruction *alloc_fn = ir_build_load_ptr(irb, scope, node, alloc_fn_ptr); - IrInstruction *maybe_coro_mem_ptr = ir_build_coro_alloc_helper(irb, scope, node, alloc_fn, coro_size); - IrInstruction *alloc_result_is_ok = ir_build_test_nonnull(irb, scope, node, maybe_coro_mem_ptr); - IrBasicBlock *alloc_err_block = ir_create_basic_block(irb, scope, "AllocError"); - IrBasicBlock *alloc_ok_block = ir_create_basic_block(irb, scope, "AllocOk"); - ir_build_cond_br(irb, scope, node, alloc_result_is_ok, alloc_ok_block, alloc_err_block, const_bool_false); + IrInstruction *alloc_fn_ptr = ir_build_field_ptr(irb, coro_scope, node, implicit_allocator_ptr, alloc_field_name); + IrInstruction *alloc_fn = ir_build_load_ptr(irb, coro_scope, node, alloc_fn_ptr); + IrInstruction *maybe_coro_mem_ptr = ir_build_coro_alloc_helper(irb, coro_scope, node, alloc_fn, coro_size); + IrInstruction *alloc_result_is_ok = ir_build_test_nonnull(irb, coro_scope, node, maybe_coro_mem_ptr); + IrBasicBlock *alloc_err_block = ir_create_basic_block(irb, coro_scope, "AllocError"); + IrBasicBlock *alloc_ok_block = ir_create_basic_block(irb, coro_scope, "AllocOk"); + ir_build_cond_br(irb, coro_scope, node, alloc_result_is_ok, alloc_ok_block, alloc_err_block, const_bool_false); ir_set_cursor_at_end_and_append_block(irb, alloc_err_block); // we can return undefined here, because the caller passes a pointer to the error struct field // in the error union result, and we populate it in case of allocation failure. - IrInstruction *undef = ir_build_const_undefined(irb, scope, node); - ir_build_return(irb, scope, node, undef); + IrInstruction *undef = ir_build_const_undefined(irb, coro_scope, node); + ir_build_return(irb, coro_scope, node, undef); ir_set_cursor_at_end_and_append_block(irb, alloc_ok_block); - IrInstruction *coro_mem_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type, maybe_coro_mem_ptr); - irb->exec->coro_handle = ir_build_coro_begin(irb, scope, node, coro_id, coro_mem_ptr); + IrInstruction *coro_mem_ptr = ir_build_ptr_cast(irb, coro_scope, node, u8_ptr_type, maybe_coro_mem_ptr); + irb->exec->coro_handle = ir_build_coro_begin(irb, coro_scope, node, coro_id, coro_mem_ptr); Buf *awaiter_handle_field_name = buf_create_from_str(AWAITER_HANDLE_FIELD_NAME); - irb->exec->coro_awaiter_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, + irb->exec->coro_awaiter_field_ptr = ir_build_field_ptr(irb, coro_scope, node, coro_promise_ptr, awaiter_handle_field_name); Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME); - irb->exec->coro_result_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_field_name); + irb->exec->coro_result_field_ptr = ir_build_field_ptr(irb, coro_scope, node, coro_promise_ptr, result_field_name); result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME); - irb->exec->coro_result_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_ptr_field_name); - ir_build_store_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr, irb->exec->coro_result_field_ptr); + irb->exec->coro_result_ptr_field_ptr = ir_build_field_ptr(irb, coro_scope, node, coro_promise_ptr, result_ptr_field_name); + ir_build_store_ptr(irb, coro_scope, node, irb->exec->coro_result_ptr_field_ptr, irb->exec->coro_result_field_ptr); irb->exec->coro_early_final = ir_create_basic_block(irb, scope, "CoroEarlyFinal"); diff --git a/test/runtime_safety.zig b/test/runtime_safety.zig index 8b8f612056..1fea6347ab 100644 --- a/test/runtime_safety.zig +++ b/test/runtime_safety.zig @@ -281,4 +281,34 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { \\ f.float = 12.34; \\} ); + + // This case makes sure that the code compiles and runs. There is not actually a special + // runtime safety check having to do specifically with error return traces across suspend points. + cases.addRuntimeSafety("error return trace across suspend points", + \\const std = @import("std"); + \\ + \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { + \\ std.os.exit(126); + \\} + \\ + \\pub fn main() void { + \\ const p = nonFailing(); + \\ resume p; + \\ const p2 = async printTrace(p) catch unreachable; + \\ cancel p2; + \\} + \\ + \\fn nonFailing() promise->error!void { + \\ return async failing() catch unreachable; + \\} + \\ + \\async fn failing() error!void { + \\ suspend; + \\ return error.Fail; + \\} + \\ + \\async fn printTrace(p: promise->error!void) void { + \\ (await p) catch unreachable; + \\} + ); } -- cgit v1.2.3 From b01c50d6fae581050affdc438942b979ae54a8da Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 30 Mar 2018 17:10:54 -0400 Subject: find libc and zig std lib at runtime this removes the following configure options: * ZIG_LIBC_LIB_DIR * ZIG_LIBC_STATIC_LIB_DIR * ZIG_LIBC_INCLUDE_DIR * ZIG_DYNAMIC_LINKER * ZIG_EACH_LIB_RPATH * zig's reliance on CMAKE_INSTALL_PREFIX these options are still available as command line options, however, the default will attempt to execute the system's C compiler to collect system defaults for these values. closes #870 --- CMakeLists.txt | 5 --- README.md | 8 +--- src/analyze.cpp | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++++---- src/codegen.cpp | 19 ++++------ src/config.h.in | 8 ---- src/link.cpp | 44 ++++++++++++++++++--- src/main.cpp | 7 ---- src/os.cpp | 17 ++++++--- src/target.cpp | 4 ++ 9 files changed, 171 insertions(+), 57 deletions(-) (limited to 'src/codegen.cpp') diff --git a/CMakeLists.txt b/CMakeLists.txt index 766a787562..1acc789de9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,11 +30,6 @@ if(GIT_EXE) endif() message("Configuring zig version ${ZIG_VERSION}") -set(ZIG_LIBC_LIB_DIR "" CACHE STRING "Default native target libc directory where crt1.o can be found") -set(ZIG_LIBC_STATIC_LIB_DIR "" CACHE STRING "Default native target libc directory where crtbeginT.o can be found") -set(ZIG_LIBC_INCLUDE_DIR "/usr/include" CACHE STRING "Default native target libc include directory") -set(ZIG_DYNAMIC_LINKER "" CACHE STRING "Override dynamic linker for native target") -set(ZIG_EACH_LIB_RPATH off CACHE BOOL "Add each dynamic library to rpath for native target") set(ZIG_STATIC off CACHE BOOL "Attempt to build a static zig executable (not compatible with glibc)") string(REGEX REPLACE "\\\\" "\\\\\\\\" ZIG_LIBC_LIB_DIR_ESCAPED "${ZIG_LIBC_LIB_DIR}") diff --git a/README.md b/README.md index acc7e891e7..d1e7e8f6d0 100644 --- a/README.md +++ b/README.md @@ -138,14 +138,10 @@ libc. Create demo games using Zig. ##### POSIX -If you have gcc or clang installed, you can find out what `ZIG_LIBC_LIB_DIR`, -`ZIG_LIBC_STATIC_LIB_DIR`, and `ZIG_LIBC_INCLUDE_DIR` should be set to -(example below). - ``` mkdir build cd build -cmake .. -DCMAKE_INSTALL_PREFIX=$(pwd) -DZIG_LIBC_LIB_DIR=$(dirname $(cc -print-file-name=crt1.o)) -DZIG_LIBC_INCLUDE_DIR=$(echo -n | cc -E -x c - -v 2>&1 | grep -B1 "End of search list." | head -n1 | cut -c 2- | sed "s/ .*//") -DZIG_LIBC_STATIC_LIB_DIR=$(dirname $(cc -print-file-name=crtbegin.o)) +cmake .. -DCMAKE_INSTALL_PREFIX=$(pwd) make make install ./zig build --build-file ../build.zig test @@ -153,8 +149,6 @@ make install ##### MacOS -`ZIG_LIBC_LIB_DIR` and `ZIG_LIBC_STATIC_LIB_DIR` are unused. - ``` brew install cmake llvm@6 brew outdated llvm@6 || brew upgrade llvm@6 diff --git a/src/analyze.cpp b/src/analyze.cpp index 2128339726..5dd15a6943 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -4285,24 +4285,117 @@ static ZigWindowsSDK *get_windows_sdk(CodeGen *g) { return g->win_sdk; } + +Buf *get_linux_libc_lib_path(const char *o_file) { + const char *cc_exe = getenv("CC"); + cc_exe = (cc_exe == nullptr) ? "cc" : cc_exe; + ZigList args = {}; + args.append(buf_ptr(buf_sprintf("-print-file-name=%s", o_file))); + Termination term; + Buf *out_stderr = buf_alloc(); + Buf *out_stdout = buf_alloc(); + int err; + if ((err = os_exec_process(cc_exe, args, &term, out_stderr, out_stdout))) { + zig_panic("unable to determine libc lib path: executing C compiler: %s", err_str(err)); + } + if (term.how != TerminationIdClean || term.code != 0) { + zig_panic("unable to determine libc lib path: executing C compiler command failed"); + } + if (buf_ends_with_str(out_stdout, "\n")) { + buf_resize(out_stdout, buf_len(out_stdout) - 1); + } + if (buf_len(out_stdout) == 0 || buf_eql_str(out_stdout, o_file)) { + zig_panic("unable to determine libc lib path: C compiler could not find %s", o_file); + } + Buf *result = buf_alloc(); + os_path_dirname(out_stdout, result); + return result; +} + +Buf *get_linux_libc_include_path(void) { + const char *cc_exe = getenv("CC"); + cc_exe = (cc_exe == nullptr) ? "cc" : cc_exe; + ZigList args = {}; + args.append("-E"); + args.append("-Wp,-v"); + args.append("-xc"); + args.append("/dev/null"); + Termination term; + Buf *out_stderr = buf_alloc(); + Buf *out_stdout = buf_alloc(); + int err; + if ((err = os_exec_process(cc_exe, args, &term, out_stderr, out_stdout))) { + zig_panic("unable to determine libc include path: executing C compiler: %s", err_str(err)); + } + if (term.how != TerminationIdClean || term.code != 0) { + zig_panic("unable to determine libc include path: executing C compiler command failed"); + } + char *prev_newline = buf_ptr(out_stderr); + ZigList search_paths = {}; + bool found_search_paths = false; + for (;;) { + char *newline = strchr(prev_newline, '\n'); + if (newline == nullptr) { + zig_panic("unable to determine libc include path: bad output from C compiler command"); + } + *newline = 0; + if (found_search_paths) { + if (strcmp(prev_newline, "End of search list.") == 0) { + break; + } + search_paths.append(prev_newline); + } else { + if (strcmp(prev_newline, "#include <...> search starts here:") == 0) { + found_search_paths = true; + } + } + prev_newline = newline + 1; + } + if (search_paths.length == 0) { + zig_panic("unable to determine libc include path: even C compiler does not know where libc headers are"); + } + for (size_t i = 0; i < search_paths.length; i += 1) { + // search in reverse order + const char *search_path = search_paths.items[search_paths.length - i - 1]; + // cut off spaces + while (*search_path == ' ') { + search_path += 1; + } + Buf *stdlib_path = buf_sprintf("%s/stdlib.h", search_path); + bool exists; + if ((err = os_file_exists(stdlib_path, &exists))) { + exists = false; + } + if (exists) { + return buf_create_from_str(search_path); + } + } + zig_panic("unable to determine libc include path: stdlib.h not found in C compiler search paths"); +} + void find_libc_include_path(CodeGen *g) { - if (!g->libc_include_dir || buf_len(g->libc_include_dir) == 0) { + if (g->libc_include_dir == nullptr) { if (g->zig_target.os == OsWindows) { ZigWindowsSDK *sdk = get_windows_sdk(g); if (os_get_win32_ucrt_include_path(sdk, g->libc_include_dir)) { zig_panic("Unable to determine libc include path."); } + } else if (g->zig_target.os == OsLinux) { + g->libc_include_dir = get_linux_libc_include_path(); + } else if (g->zig_target.os == OsMacOSX) { + g->libc_include_dir = buf_create_from_str("/usr/include"); + } else { + // TODO find libc at runtime for other operating systems + zig_panic("Unable to determine libc include path."); } - - // TODO find libc at runtime for other operating systems - zig_panic("Unable to determine libc include path."); } + assert(buf_len(g->libc_include_dir) != 0); } void find_libc_lib_path(CodeGen *g) { // later we can handle this better by reporting an error via the normal mechanism - if (!g->libc_lib_dir || buf_len(g->libc_lib_dir) == 0 || + if (g->libc_lib_dir == nullptr || (g->zig_target.os == OsWindows && (g->msvc_lib_dir == nullptr || g->kernel32_lib_dir == nullptr))) { if (g->zig_target.os == OsWindows) { @@ -4326,18 +4419,25 @@ void find_libc_lib_path(CodeGen *g) { g->msvc_lib_dir = vc_lib_dir; g->libc_lib_dir = ucrt_lib_path; g->kernel32_lib_dir = kern_lib_path; + } else if (g->zig_target.os == OsLinux) { + g->libc_lib_dir = get_linux_libc_lib_path("crt1.o"); } else { zig_panic("Unable to determine libc lib path."); } + } else { + assert(buf_len(g->libc_lib_dir) != 0); } - if (!g->libc_static_lib_dir || buf_len(g->libc_static_lib_dir) == 0) { + if (g->libc_static_lib_dir == nullptr) { if ((g->zig_target.os == OsWindows) && (g->msvc_lib_dir != NULL)) { return; - } - else { + } else if (g->zig_target.os == OsLinux) { + g->libc_static_lib_dir = get_linux_libc_lib_path("crtbegin.o"); + } else { zig_panic("Unable to determine libc static lib path."); } + } else { + assert(buf_len(g->libc_static_lib_dir) != 0); } } diff --git a/src/codegen.cpp b/src/codegen.cpp index 25b2ffbf16..0ebdf7fa3d 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -112,10 +112,10 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out // that's for native compilation g->zig_target = *target; resolve_target_object_format(&g->zig_target); - g->dynamic_linker = buf_create_from_str(""); - g->libc_lib_dir = buf_create_from_str(""); - g->libc_static_lib_dir = buf_create_from_str(""); - g->libc_include_dir = buf_create_from_str(""); + g->dynamic_linker = nullptr; + g->libc_lib_dir = nullptr; + g->libc_static_lib_dir = nullptr; + g->libc_include_dir = nullptr; g->msvc_lib_dir = nullptr; g->kernel32_lib_dir = nullptr; g->each_lib_rpath = false; @@ -123,16 +123,13 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out // native compilation, we can rely on the configuration stuff g->is_native_target = true; get_native_target(&g->zig_target); - g->dynamic_linker = buf_create_from_str(ZIG_DYNAMIC_LINKER); - g->libc_lib_dir = buf_create_from_str(ZIG_LIBC_LIB_DIR); - g->libc_static_lib_dir = buf_create_from_str(ZIG_LIBC_STATIC_LIB_DIR); - g->libc_include_dir = buf_create_from_str(ZIG_LIBC_INCLUDE_DIR); + g->dynamic_linker = nullptr; // find it at runtime + g->libc_lib_dir = nullptr; // find it at runtime + g->libc_static_lib_dir = nullptr; // find it at runtime + g->libc_include_dir = nullptr; // find it at runtime g->msvc_lib_dir = nullptr; // find it at runtime g->kernel32_lib_dir = nullptr; // find it at runtime - -#ifdef ZIG_EACH_LIB_RPATH g->each_lib_rpath = true; -#endif if (g->zig_target.os == OsMacOSX || g->zig_target.os == OsIOS) diff --git a/src/config.h.in b/src/config.h.in index 1fcc3fe12c..16896273b3 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -13,14 +13,6 @@ #define ZIG_VERSION_PATCH @ZIG_VERSION_PATCH@ #define ZIG_VERSION_STRING "@ZIG_VERSION@" -#define ZIG_INSTALL_PREFIX "@CMAKE_INSTALL_PREFIX@" -#define ZIG_LIBC_INCLUDE_DIR "@ZIG_LIBC_INCLUDE_DIR_ESCAPED@" -#define ZIG_LIBC_LIB_DIR "@ZIG_LIBC_LIB_DIR_ESCAPED@" -#define ZIG_LIBC_STATIC_LIB_DIR "@ZIG_LIBC_STATIC_LIB_DIR_ESCAPED@" -#define ZIG_DYNAMIC_LINKER "@ZIG_DYNAMIC_LINKER@" - -#cmakedefine ZIG_EACH_LIB_RPATH - // Only used for running tests before installing. #define ZIG_TEST_DIR "@CMAKE_SOURCE_DIR@/test" diff --git a/src/link.cpp b/src/link.cpp index f0537ffa0f..57fa59b675 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -164,6 +164,34 @@ static void add_rpath(LinkJob *lj, Buf *rpath) { lj->rpath_table.put(rpath, true); } +static Buf *get_dynamic_linker_path(CodeGen *g) { + if (g->is_native_target && g->zig_target.arch.arch == ZigLLVM_x86_64) { + const char *cc_exe = getenv("CC"); + cc_exe = (cc_exe == nullptr) ? "cc" : cc_exe; + ZigList args = {}; + args.append("-print-file-name=ld-linux-x86-64.so.2"); + Termination term; + Buf *out_stderr = buf_alloc(); + Buf *out_stdout = buf_alloc(); + int err; + if ((err = os_exec_process(cc_exe, args, &term, out_stderr, out_stdout))) { + return target_dynamic_linker(&g->zig_target); + } + if (term.how != TerminationIdClean || term.code != 0) { + return target_dynamic_linker(&g->zig_target); + } + if (buf_ends_with_str(out_stdout, "\n")) { + buf_resize(out_stdout, buf_len(out_stdout) - 1); + } + if (buf_len(out_stdout) == 0 || buf_eql_str(out_stdout, "ld-linux-x86-64.so.2")) { + return target_dynamic_linker(&g->zig_target); + } + return out_stdout; + } else { + return target_dynamic_linker(&g->zig_target); + } +} + static void construct_linker_job_elf(LinkJob *lj) { CodeGen *g = lj->codegen; @@ -259,12 +287,16 @@ static void construct_linker_job_elf(LinkJob *lj) { lj->args.append(buf_ptr(g->libc_static_lib_dir)); } - if (g->dynamic_linker && buf_len(g->dynamic_linker) > 0) { - lj->args.append("-dynamic-linker"); - lj->args.append(buf_ptr(g->dynamic_linker)); - } else { - lj->args.append("-dynamic-linker"); - lj->args.append(buf_ptr(target_dynamic_linker(&g->zig_target))); + if (!g->is_static) { + if (g->dynamic_linker != nullptr) { + assert(buf_len(g->dynamic_linker) != 0); + lj->args.append("-dynamic-linker"); + lj->args.append(buf_ptr(g->dynamic_linker)); + } else { + Buf *resolved_dynamic_linker = get_dynamic_linker_path(g); + lj->args.append("-dynamic-linker"); + lj->args.append(buf_ptr(resolved_dynamic_linker)); + } } if (shared) { diff --git a/src/main.cpp b/src/main.cpp index 791cb3b1b5..f2f4cc970e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -195,13 +195,6 @@ static int find_zig_lib_dir(Buf *out_path) { } } - if (ZIG_INSTALL_PREFIX != nullptr) { - if (test_zig_install_prefix(buf_create_from_str(ZIG_INSTALL_PREFIX), out_path)) { - return 0; - } - } - - return ErrorFileNotFound; } diff --git a/src/os.cpp b/src/os.cpp index e312854612..90eecef3cf 100644 --- a/src/os.cpp +++ b/src/os.cpp @@ -57,10 +57,6 @@ static clock_serv_t cclock; #include #include -// these implementations are lazy. But who cares, we'll make a robust -// implementation in the zig standard library and then this code all gets -// deleted when we self-host. it works for now. - #if defined(ZIG_OS_POSIX) static void populate_termination(Termination *term, int status) { if (WIFEXITED(status)) { @@ -929,7 +925,18 @@ int os_self_exe_path(Buf *out_path) { #elif defined(ZIG_OS_DARWIN) return ErrorFileNotFound; #elif defined(ZIG_OS_LINUX) - return ErrorFileNotFound; + buf_resize(out_path, 256); + for (;;) { + ssize_t amt = readlink("/proc/self/exe", buf_ptr(out_path), buf_len(out_path)); + if (amt == -1) { + return ErrorUnexpected; + } + if (amt == (ssize_t)buf_len(out_path)) { + buf_resize(out_path, buf_len(out_path) * 2); + continue; + } + return 0; + } #endif return ErrorFileNotFound; } diff --git a/src/target.cpp b/src/target.cpp index 8e7c5ce578..5008b51a09 100644 --- a/src/target.cpp +++ b/src/target.cpp @@ -863,6 +863,10 @@ Buf *target_dynamic_linker(ZigTarget *target) { env == ZigLLVM_GNUX32) { return buf_create_from_str("/libx32/ld-linux-x32.so.2"); + } else if (arch == ZigLLVM_x86_64 && + (env == ZigLLVM_Musl || env == ZigLLVM_MuslEABI || env == ZigLLVM_MuslEABIHF)) + { + return buf_create_from_str("/lib/ld-musl-x86_64.so.1"); } else { return buf_create_from_str("/lib64/ld-linux-x86-64.so.2"); } -- cgit v1.2.3 From 2e5115b0687ee9b7078dbf70da7d7070a7c80399 Mon Sep 17 00:00:00 2001 From: Marc Tiehuis Date: Sat, 31 Mar 2018 19:04:01 +1300 Subject: Add run compiler command 'zig run file.zig' builds a file and stores the artifacts in the global cache. On successful compilation the binary is executed. 'zig run file.zig -- a b c' does the same, but passes the arguments a, b and c as runtime arguments to the program. Everything after an '--' are treated as runtime arguments. On a posix system, a shebang can be used to run a zig file directly. An example shebang would be '#!/usr/bin/zig run'. You may not be able pass extra compile arguments currently as part of the shebang. Linux for example treats all arguments after the first as a single argument which will result in an 'invalid command'. Currently there is no customisability for the cache path as a compile argument. For a posix system you can use `TMPDIR=. zig run file.zig` to override, in this case using the current directory for the run cache. The input file is always recompiled, even if it has changed. This is intended to be cached but further discussion/thought needs to go into this. Closes #466. --- src/codegen.cpp | 6 ++--- src/ir.cpp | 4 +-- src/main.cpp | 58 ++++++++++++++++++++++++++++++++++++++------ src/os.cpp | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- src/os.hpp | 6 +++-- 5 files changed, 129 insertions(+), 20 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index 0ebdf7fa3d..bdd28b86fd 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -6286,7 +6286,7 @@ static ImportTableEntry *add_special_code(CodeGen *g, PackageTableEntry *package zig_panic("unable to open '%s': %s", buf_ptr(&path_to_code_src), err_str(err)); } Buf *import_code = buf_alloc(); - if ((err = os_fetch_file_path(abs_full_path, import_code))) { + if ((err = os_fetch_file_path(abs_full_path, import_code, false))) { zig_panic("unable to open '%s': %s", buf_ptr(&path_to_code_src), err_str(err)); } @@ -6374,7 +6374,7 @@ static void gen_root_source(CodeGen *g) { } Buf *source_code = buf_alloc(); - if ((err = os_fetch_file_path(rel_full_path, source_code))) { + if ((err = os_fetch_file_path(rel_full_path, source_code, true))) { zig_panic("unable to open '%s': %s", buf_ptr(rel_full_path), err_str(err)); } @@ -6439,7 +6439,7 @@ static void gen_global_asm(CodeGen *g) { int err; for (size_t i = 0; i < g->assembly_files.length; i += 1) { Buf *asm_file = g->assembly_files.at(i); - if ((err = os_fetch_file_path(asm_file, &contents))) { + if ((err = os_fetch_file_path(asm_file, &contents, false))) { zig_panic("Unable to read %s: %s", buf_ptr(asm_file), err_str(err)); } buf_append_buf(&g->global_asm, &contents); diff --git a/src/ir.cpp b/src/ir.cpp index 18fd02c297..4fe6769f78 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -14709,7 +14709,7 @@ static TypeTableEntry *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructi return ira->codegen->builtin_types.entry_namespace; } - if ((err = os_fetch_file_path(abs_full_path, import_code))) { + if ((err = os_fetch_file_path(abs_full_path, import_code, true))) { if (err == ErrorFileNotFound) { ir_add_error_node(ira, source_node, buf_sprintf("unable to find '%s'", buf_ptr(import_target_path))); @@ -15570,7 +15570,7 @@ static TypeTableEntry *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstr // load from file system into const expr Buf *file_contents = buf_alloc(); int err; - if ((err = os_fetch_file_path(&file_path, file_contents))) { + if ((err = os_fetch_file_path(&file_path, file_contents, false))) { if (err == ErrorFileNotFound) { ir_add_error(ira, instruction->name, buf_sprintf("unable to find '%s'", buf_ptr(&file_path))); return ira->codegen->builtin_types.entry_invalid; diff --git a/src/main.cpp b/src/main.cpp index f2f4cc970e..63b077e833 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -23,6 +23,7 @@ static int usage(const char *arg0) { " build-exe [source] create executable from source or object files\n" " build-lib [source] create library from source or object files\n" " build-obj [source] create object from source or assembly\n" + " run [source] create executable and run immediately\n" " translate-c [source] convert c code to zig code\n" " targets list available compilation targets\n" " test [source] create and run a test build\n" @@ -220,6 +221,7 @@ static Buf *resolve_zig_lib_dir(const char *zig_install_prefix_arg) { enum Cmd { CmdInvalid, CmdBuild, + CmdRun, CmdTest, CmdVersion, CmdZen, @@ -329,6 +331,8 @@ int main(int argc, char **argv) { CliPkg *cur_pkg = allocate(1); BuildMode build_mode = BuildModeDebug; ZigList test_exec_args = {0}; + int comptime_args_end = 0; + int runtime_args_start = argc; if (argc >= 2 && strcmp(argv[1], "build") == 0) { const char *zig_exe_path = arg0; @@ -481,11 +485,15 @@ int main(int argc, char **argv) { return (term.how == TerminationIdClean) ? term.code : -1; } - for (int i = 1; i < argc; i += 1) { + for (int i = 1; i < argc; i += 1, comptime_args_end += 1) { char *arg = argv[i]; if (arg[0] == '-') { - if (strcmp(arg, "--release-fast") == 0) { + if (strcmp(arg, "--") == 0) { + // ignore -- from both compile and runtime arg sets + runtime_args_start = i + 1; + break; + } else if (strcmp(arg, "--release-fast") == 0) { build_mode = BuildModeFastRelease; } else if (strcmp(arg, "--release-safe") == 0) { build_mode = BuildModeSafeRelease; @@ -652,6 +660,9 @@ int main(int argc, char **argv) { } else if (strcmp(arg, "build-lib") == 0) { cmd = CmdBuild; out_type = OutTypeLib; + } else if (strcmp(arg, "run") == 0) { + cmd = CmdRun; + out_type = OutTypeExe; } else if (strcmp(arg, "version") == 0) { cmd = CmdVersion; } else if (strcmp(arg, "zen") == 0) { @@ -670,6 +681,7 @@ int main(int argc, char **argv) { } else { switch (cmd) { case CmdBuild: + case CmdRun: case CmdTranslateC: case CmdTest: if (!in_file) { @@ -724,8 +736,8 @@ int main(int argc, char **argv) { } } - switch (cmd) { + case CmdRun: case CmdBuild: case CmdTranslateC: case CmdTest: @@ -733,7 +745,7 @@ int main(int argc, char **argv) { if (cmd == CmdBuild && !in_file && objects.length == 0 && asm_files.length == 0) { fprintf(stderr, "Expected source file argument or at least one --object or --assembly argument.\n"); return usage(arg0); - } else if ((cmd == CmdTranslateC || cmd == CmdTest) && !in_file) { + } else if ((cmd == CmdTranslateC || cmd == CmdTest || cmd == CmdRun) && !in_file) { fprintf(stderr, "Expected source file argument.\n"); return usage(arg0); } else if (cmd == CmdBuild && out_type == OutTypeObj && objects.length != 0) { @@ -745,6 +757,10 @@ int main(int argc, char **argv) { bool need_name = (cmd == CmdBuild || cmd == CmdTranslateC); + if (cmd == CmdRun) { + out_name = "run"; + } + Buf *in_file_buf = nullptr; Buf *buf_out_name = (cmd == CmdTest) ? buf_create_from_str("test") : @@ -769,9 +785,23 @@ int main(int argc, char **argv) { Buf *zig_root_source_file = (cmd == CmdTranslateC) ? nullptr : in_file_buf; Buf *full_cache_dir = buf_alloc(); - os_path_resolve(buf_create_from_str("."), - buf_create_from_str((cache_dir == nullptr) ? default_zig_cache_name : cache_dir), - full_cache_dir); + Buf *run_exec_path = buf_alloc(); + if (cmd == CmdRun) { + if (buf_out_name == nullptr) { + buf_out_name = buf_create_from_str("run"); + } + + Buf *global_cache_dir = buf_alloc(); + os_get_global_cache_directory(global_cache_dir); + os_path_join(global_cache_dir, buf_out_name, run_exec_path); + os_path_resolve(buf_create_from_str("."), global_cache_dir, full_cache_dir); + + out_file = buf_ptr(run_exec_path); + } else { + os_path_resolve(buf_create_from_str("."), + buf_create_from_str((cache_dir == nullptr) ? default_zig_cache_name : cache_dir), + full_cache_dir); + } Buf *zig_lib_dir_buf = resolve_zig_lib_dir(zig_install_prefix); @@ -855,7 +885,7 @@ int main(int argc, char **argv) { add_package(g, cur_pkg, g->root_package); - if (cmd == CmdBuild) { + if (cmd == CmdBuild || cmd == CmdRun) { codegen_set_emit_file_type(g, emit_file_type); for (size_t i = 0; i < objects.length; i += 1) { @@ -868,6 +898,18 @@ int main(int argc, char **argv) { codegen_link(g, out_file); if (timing_info) codegen_print_timing_report(g, stdout); + + if (cmd == CmdRun) { + ZigList args = {0}; + for (int i = runtime_args_start; i < argc; ++i) { + args.append(argv[i]); + } + + Termination term; + os_spawn_process(buf_ptr(run_exec_path), args, &term); + return term.code; + } + return EXIT_SUCCESS; } else if (cmd == CmdTranslateC) { codegen_translate_c(g, in_file_buf); diff --git a/src/os.cpp b/src/os.cpp index de1a1f21d2..e0491b21de 100644 --- a/src/os.cpp +++ b/src/os.cpp @@ -288,13 +288,39 @@ void os_path_resolve(Buf *ref_path, Buf *target_path, Buf *out_abs_path) { return; } -int os_fetch_file(FILE *f, Buf *out_buf) { +int os_fetch_file(FILE *f, Buf *out_buf, bool skip_shebang) { static const ssize_t buf_size = 0x2000; buf_resize(out_buf, buf_size); ssize_t actual_buf_len = 0; + + bool first_read = true; + for (;;) { size_t amt_read = fread(buf_ptr(out_buf) + actual_buf_len, 1, buf_size, f); actual_buf_len += amt_read; + + if (skip_shebang && first_read && buf_starts_with_str(out_buf, "#!")) { + size_t i = 0; + while (true) { + if (i > buf_len(out_buf)) { + zig_panic("shebang line exceeded %zd characters", buf_size); + } + + size_t current_pos = i; + i += 1; + + if (out_buf->list.at(current_pos) == '\n') { + break; + } + } + + ZigList *list = &out_buf->list; + memmove(list->items, list->items + i, list->length - i); + list->length -= i; + + actual_buf_len -= i; + } + if (amt_read != buf_size) { if (feof(f)) { buf_resize(out_buf, actual_buf_len); @@ -305,6 +331,7 @@ int os_fetch_file(FILE *f, Buf *out_buf) { } buf_resize(out_buf, actual_buf_len + buf_size); + first_read = false; } zig_unreachable(); } @@ -374,8 +401,8 @@ static int os_exec_process_posix(const char *exe, ZigList &args, FILE *stdout_f = fdopen(stdout_pipe[0], "rb"); FILE *stderr_f = fdopen(stderr_pipe[0], "rb"); - os_fetch_file(stdout_f, out_stdout); - os_fetch_file(stderr_f, out_stderr); + os_fetch_file(stdout_f, out_stdout, false); + os_fetch_file(stderr_f, out_stderr, false); fclose(stdout_f); fclose(stderr_f); @@ -588,7 +615,7 @@ int os_copy_file(Buf *src_path, Buf *dest_path) { } } -int os_fetch_file_path(Buf *full_path, Buf *out_contents) { +int os_fetch_file_path(Buf *full_path, Buf *out_contents, bool skip_shebang) { FILE *f = fopen(buf_ptr(full_path), "rb"); if (!f) { switch (errno) { @@ -607,7 +634,7 @@ int os_fetch_file_path(Buf *full_path, Buf *out_contents) { return ErrorFileSystem; } } - int result = os_fetch_file(f, out_contents); + int result = os_fetch_file(f, out_contents, skip_shebang); fclose(f); return result; } @@ -780,6 +807,44 @@ int os_buf_to_tmp_file(Buf *contents, Buf *suffix, Buf *out_tmp_path) { #endif } +#if defined(ZIG_OS_POSIX) +int os_get_global_cache_directory(Buf *out_tmp_path) { + const char *tmp_dir = getenv("TMPDIR"); + if (!tmp_dir) { + tmp_dir = P_tmpdir; + } + + Buf *tmp_dir_buf = buf_create_from_str(tmp_dir); + Buf *cache_dirname_buf = buf_create_from_str("zig-cache"); + + buf_resize(out_tmp_path, 0); + os_path_join(tmp_dir_buf, cache_dirname_buf, out_tmp_path); + + buf_deinit(tmp_dir_buf); + buf_deinit(cache_dirname_buf); + return 0; +} +#endif + +#if defined(ZIG_OS_WINDOWS) +int os_get_global_cache_directory(Buf *out_tmp_path) { + char tmp_dir[MAX_PATH + 1]; + if (GetTempPath(MAX_PATH, tmp_dir) == 0) { + zig_panic("GetTempPath failed"); + } + + Buf *tmp_dir_buf = buf_create_from_str(tmp_dir); + Buf *cache_dirname_buf = buf_create_from_str("zig-cache"); + + buf_resize(out_tmp_path, 0); + os_path_join(tmp_dir_buf, cache_dirname_buf, out_tmp_path); + + buf_deinit(tmp_dir_buf); + buf_deinit(cache_dirname_buf); + return 0; +} +#endif + int os_delete_file(Buf *path) { if (remove(buf_ptr(path))) { return ErrorFileSystem; diff --git a/src/os.hpp b/src/os.hpp index 5d29db0d07..b94e98ec3d 100644 --- a/src/os.hpp +++ b/src/os.hpp @@ -51,14 +51,16 @@ int os_path_real(Buf *rel_path, Buf *out_abs_path); void os_path_resolve(Buf *ref_path, Buf *target_path, Buf *out_abs_path); bool os_path_is_absolute(Buf *path); +int os_get_global_cache_directory(Buf *out_tmp_path); + int os_make_path(Buf *path); int os_make_dir(Buf *path); void os_write_file(Buf *full_path, Buf *contents); int os_copy_file(Buf *src_path, Buf *dest_path); -int os_fetch_file(FILE *file, Buf *out_contents); -int os_fetch_file_path(Buf *full_path, Buf *out_contents); +int os_fetch_file(FILE *file, Buf *out_contents, bool skip_shebang); +int os_fetch_file_path(Buf *full_path, Buf *out_contents, bool skip_shebang); int os_get_cwd(Buf *out_cwd); -- cgit v1.2.3