authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-04-02 18:19:59-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-04-02 18:19:59-04:00
log8fd0fddce5d44344dd7914ae86a4d976b99f9cc3
tree69d6a1b6e32e8c8a622eb149c0e60f33f426996d
parent0594487a2e98e18a18c0c6bdb2532c5e36fc6ea7

zig build system progress

* In-progress os.ChildProcess.spawn implementation. See #204 * Add explicit cast from integer to error. Closes #294 * fix casting from error to integer * fix compiler crash when initializing variable to undefined with no type

11 files changed, 742 insertions(+), 51 deletions(-)

src/all_types.hpp+15-1
...@@ -520,7 +520,6 @@ struct AstNodeUnwrapErrorExpr {...@@ -520,7 +520,6 @@ struct AstNodeUnwrapErrorExpr {
520enum CastOp {520enum CastOp {
521 CastOpNoCast, // signifies the function call expression is not a cast521 CastOpNoCast, // signifies the function call expression is not a cast
522 CastOpNoop, // fn call expr is a cast, but does nothing522 CastOpNoop, // fn call expr is a cast, but does nothing
523 CastOpErrToInt,
524 CastOpIntToFloat,523 CastOpIntToFloat,
525 CastOpFloatToInt,524 CastOpFloatToInt,
526 CastOpBoolToInt,525 CastOpBoolToInt,
...@@ -1223,6 +1222,7 @@ enum PanicMsgId {...@@ -1223,6 +1222,7 @@ enum PanicMsgId {
1223 PanicMsgIdSliceWidenRemainder,1222 PanicMsgIdSliceWidenRemainder,
1224 PanicMsgIdUnwrapMaybeFail,1223 PanicMsgIdUnwrapMaybeFail,
1225 PanicMsgIdUnwrapErrFail,1224 PanicMsgIdUnwrapErrFail,
1225 PanicMsgIdInvalidErrorCode,
12261226
1227 PanicMsgIdCount,1227 PanicMsgIdCount,
1228};1228};
...@@ -1728,6 +1728,8 @@ enum IrInstructionId {...@@ -1728,6 +1728,8 @@ enum IrInstructionId {
1728 IrInstructionIdIntToPtr,1728 IrInstructionIdIntToPtr,
1729 IrInstructionIdPtrToInt,1729 IrInstructionIdPtrToInt,
1730 IrInstructionIdIntToEnum,1730 IrInstructionIdIntToEnum,
1731 IrInstructionIdIntToErr,
1732 IrInstructionIdErrToInt,
1731 IrInstructionIdCheckSwitchProngs,1733 IrInstructionIdCheckSwitchProngs,
1732 IrInstructionIdTestType,1734 IrInstructionIdTestType,
1733 IrInstructionIdTypeName,1735 IrInstructionIdTypeName,
...@@ -2404,6 +2406,18 @@ struct IrInstructionIntToEnum {...@@ -2404,6 +2406,18 @@ struct IrInstructionIntToEnum {
2404 IrInstruction *target;2406 IrInstruction *target;
2405};2407};
24062408
2409struct IrInstructionIntToErr {
2410 IrInstruction base;
2411
2412 IrInstruction *target;
2413};
2414
2415struct IrInstructionErrToInt {
2416 IrInstruction base;
2417
2418 IrInstruction *target;
2419};
2420
2407struct IrInstructionCheckSwitchProngsRange {2421struct IrInstructionCheckSwitchProngsRange {
2408 IrInstruction *start;2422 IrInstruction *start;
2409 IrInstruction *end;2423 IrInstruction *end;
src/codegen.cpp+66-8
...@@ -570,6 +570,8 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {...@@ -570,6 +570,8 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {
570 return buf_create_from_str("attempt to unwrap error");570 return buf_create_from_str("attempt to unwrap error");
571 case PanicMsgIdUnreachable:571 case PanicMsgIdUnreachable:
572 return buf_create_from_str("reached unreachable code");572 return buf_create_from_str("reached unreachable code");
573 case PanicMsgIdInvalidErrorCode:
574 return buf_create_from_str("invalid error code");
573 }575 }
574 zig_unreachable();576 zig_unreachable();
575}577}
...@@ -1227,14 +1229,6 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,...@@ -1227,14 +1229,6 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
1227 zig_unreachable();1229 zig_unreachable();
1228 case CastOpNoop:1230 case CastOpNoop:
1229 return expr_val;1231 return expr_val;
1230 case CastOpErrToInt:
1231 assert(actual_type->id == TypeTableEntryIdErrorUnion);
1232 if (!type_has_bits(actual_type->data.error.child_type)) {
1233 return gen_widen_or_shorten(g, ir_want_debug_safety(g, &cast_instruction->base),
1234 g->err_tag_type, wanted_type, expr_val);
1235 } else {
1236 zig_panic("TODO");
1237 }
1238 case CastOpResizeSlice:1232 case CastOpResizeSlice:
1239 {1233 {
1240 assert(cast_instruction->tmp_ptr);1234 assert(cast_instruction->tmp_ptr);
...@@ -1402,6 +1396,66 @@ static LLVMValueRef ir_render_int_to_enum(CodeGen *g, IrExecutable *executable,...@@ -1402,6 +1396,66 @@ static LLVMValueRef ir_render_int_to_enum(CodeGen *g, IrExecutable *executable,
1402 instruction->target->value.type, wanted_int_type, target_val);1396 instruction->target->value.type, wanted_int_type, target_val);
1403}1397}
14041398
1399static LLVMValueRef ir_render_int_to_err(CodeGen *g, IrExecutable *executable, IrInstructionIntToErr *instruction) {
1400 TypeTableEntry *wanted_type = instruction->base.value.type;
1401 assert(wanted_type->id == TypeTableEntryIdPureError);
1402
1403 TypeTableEntry *actual_type = instruction->target->value.type;
1404 assert(actual_type->id == TypeTableEntryIdInt);
1405 assert(!actual_type->data.integral.is_signed);
1406
1407 LLVMValueRef target_val = ir_llvm_value(g, instruction->target);
1408
1409 if (ir_want_debug_safety(g, &instruction->base)) {
1410 LLVMValueRef zero = LLVMConstNull(actual_type->type_ref);
1411 LLVMValueRef neq_zero_bit = LLVMBuildICmp(g->builder, LLVMIntNE, target_val, zero, "");
1412 LLVMValueRef ok_bit;
1413 uint64_t biggest_possible_err_val = max_unsigned_val(actual_type);
1414 if (biggest_possible_err_val < g->error_decls.length) {
1415 ok_bit = neq_zero_bit;
1416 } else {
1417 LLVMValueRef error_value_count = LLVMConstInt(actual_type->type_ref, g->error_decls.length, false);
1418 LLVMValueRef in_bounds_bit = LLVMBuildICmp(g->builder, LLVMIntULT, target_val, error_value_count, "");
1419 ok_bit = LLVMBuildAnd(g->builder, neq_zero_bit, in_bounds_bit, "");
1420 }
1421
1422 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "IntToErrOk");
1423 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "IntToErrFail");
1424
1425 LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
1426
1427 LLVMPositionBuilderAtEnd(g->builder, fail_block);
1428 gen_debug_safety_crash(g, PanicMsgIdInvalidErrorCode);
1429
1430 LLVMPositionBuilderAtEnd(g->builder, ok_block);
1431 }
1432
1433 return gen_widen_or_shorten(g, false, actual_type, g->err_tag_type, target_val);
1434}
1435
1436static LLVMValueRef ir_render_err_to_int(CodeGen *g, IrExecutable *executable, IrInstructionErrToInt *instruction) {
1437 TypeTableEntry *wanted_type = instruction->base.value.type;
1438 assert(wanted_type->id == TypeTableEntryIdInt);
1439 assert(!wanted_type->data.integral.is_signed);
1440
1441 TypeTableEntry *actual_type = instruction->target->value.type;
1442 LLVMValueRef target_val = ir_llvm_value(g, instruction->target);
1443
1444 if (actual_type->id == TypeTableEntryIdPureError) {
1445 return gen_widen_or_shorten(g, ir_want_debug_safety(g, &instruction->base),
1446 g->err_tag_type, wanted_type, target_val);
1447 } else if (actual_type->id == TypeTableEntryIdErrorUnion) {
1448 if (!type_has_bits(actual_type->data.error.child_type)) {
1449 return gen_widen_or_shorten(g, ir_want_debug_safety(g, &instruction->base),
1450 g->err_tag_type, wanted_type, target_val);
1451 } else {
1452 zig_panic("TODO");
1453 }
1454 } else {
1455 zig_unreachable();
1456 }
1457}
1458
1405static LLVMValueRef ir_render_unreachable(CodeGen *g, IrExecutable *executable,1459static LLVMValueRef ir_render_unreachable(CodeGen *g, IrExecutable *executable,
1406 IrInstructionUnreachable *unreachable_instruction)1460 IrInstructionUnreachable *unreachable_instruction)
1407{1461{
...@@ -2786,6 +2840,10 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -2786,6 +2840,10 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
2786 return ir_render_int_to_ptr(g, executable, (IrInstructionIntToPtr *)instruction);2840 return ir_render_int_to_ptr(g, executable, (IrInstructionIntToPtr *)instruction);
2787 case IrInstructionIdIntToEnum:2841 case IrInstructionIdIntToEnum:
2788 return ir_render_int_to_enum(g, executable, (IrInstructionIntToEnum *)instruction);2842 return ir_render_int_to_enum(g, executable, (IrInstructionIntToEnum *)instruction);
2843 case IrInstructionIdIntToErr:
2844 return ir_render_int_to_err(g, executable, (IrInstructionIntToErr *)instruction);
2845 case IrInstructionIdErrToInt:
2846 return ir_render_err_to_int(g, executable, (IrInstructionErrToInt *)instruction);
2789 case IrInstructionIdContainerInitList:2847 case IrInstructionIdContainerInitList:
2790 return ir_render_container_init_list(g, executable, (IrInstructionContainerInitList *)instruction);2848 return ir_render_container_init_list(g, executable, (IrInstructionContainerInitList *)instruction);
2791 case IrInstructionIdPanic:2849 case IrInstructionIdPanic:
src/ir.cpp+148-28
...@@ -500,6 +500,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionIntToEnum *) {...@@ -500,6 +500,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionIntToEnum *) {
500 return IrInstructionIdIntToEnum;500 return IrInstructionIdIntToEnum;
501}501}
502502
503static constexpr IrInstructionId ir_instruction_id(IrInstructionIntToErr *) {
504 return IrInstructionIdIntToErr;
505}
506
507static constexpr IrInstructionId ir_instruction_id(IrInstructionErrToInt *) {
508 return IrInstructionIdErrToInt;
509}
510
503static constexpr IrInstructionId ir_instruction_id(IrInstructionCheckSwitchProngs *) {511static constexpr IrInstructionId ir_instruction_id(IrInstructionCheckSwitchProngs *) {
504 return IrInstructionIdCheckSwitchProngs;512 return IrInstructionIdCheckSwitchProngs;
505}513}
...@@ -2002,6 +2010,30 @@ static IrInstruction *ir_build_int_to_enum(IrBuilder *irb, Scope *scope, AstNode...@@ -2002,6 +2010,30 @@ static IrInstruction *ir_build_int_to_enum(IrBuilder *irb, Scope *scope, AstNode
2002 return &instruction->base;2010 return &instruction->base;
2003}2011}
20042012
2013static IrInstruction *ir_build_int_to_err(IrBuilder *irb, Scope *scope, AstNode *source_node,
2014 IrInstruction *target)
2015{
2016 IrInstructionIntToErr *instruction = ir_build_instruction<IrInstructionIntToErr>(
2017 irb, scope, source_node);
2018 instruction->target = target;
2019
2020 ir_ref_instruction(target, irb->current_basic_block);
2021
2022 return &instruction->base;
2023}
2024
2025static IrInstruction *ir_build_err_to_int(IrBuilder *irb, Scope *scope, AstNode *source_node,
2026 IrInstruction *target)
2027{
2028 IrInstructionErrToInt *instruction = ir_build_instruction<IrInstructionErrToInt>(
2029 irb, scope, source_node);
2030 instruction->target = target;
2031
2032 ir_ref_instruction(target, irb->current_basic_block);
2033
2034 return &instruction->base;
2035}
2036
2005static IrInstruction *ir_build_check_switch_prongs(IrBuilder *irb, Scope *scope, AstNode *source_node,2037static IrInstruction *ir_build_check_switch_prongs(IrBuilder *irb, Scope *scope, AstNode *source_node,
2006 IrInstruction *target_value, IrInstructionCheckSwitchProngsRange *ranges, size_t range_count)2038 IrInstruction *target_value, IrInstructionCheckSwitchProngsRange *ranges, size_t range_count)
2007{2039{
...@@ -2704,6 +2736,20 @@ static IrInstruction *ir_instruction_inttoenum_get_dep(IrInstructionIntToEnum *i...@@ -2704,6 +2736,20 @@ static IrInstruction *ir_instruction_inttoenum_get_dep(IrInstructionIntToEnum *i
2704 }2736 }
2705}2737}
27062738
2739static IrInstruction *ir_instruction_inttoerr_get_dep(IrInstructionIntToErr *instruction, size_t index) {
2740 switch (index) {
2741 case 0: return instruction->target;
2742 default: return nullptr;
2743 }
2744}
2745
2746static IrInstruction *ir_instruction_errtoint_get_dep(IrInstructionErrToInt *instruction, size_t index) {
2747 switch (index) {
2748 case 0: return instruction->target;
2749 default: return nullptr;
2750 }
2751}
2752
2707static IrInstruction *ir_instruction_checkswitchprongs_get_dep(IrInstructionCheckSwitchProngs *instruction,2753static IrInstruction *ir_instruction_checkswitchprongs_get_dep(IrInstructionCheckSwitchProngs *instruction,
2708 size_t index)2754 size_t index)
2709{2755{
...@@ -2938,6 +2984,10 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t...@@ -2938,6 +2984,10 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
2938 return ir_instruction_ptrtoint_get_dep((IrInstructionPtrToInt *) instruction, index);2984 return ir_instruction_ptrtoint_get_dep((IrInstructionPtrToInt *) instruction, index);
2939 case IrInstructionIdIntToEnum:2985 case IrInstructionIdIntToEnum:
2940 return ir_instruction_inttoenum_get_dep((IrInstructionIntToEnum *) instruction, index);2986 return ir_instruction_inttoenum_get_dep((IrInstructionIntToEnum *) instruction, index);
2987 case IrInstructionIdIntToErr:
2988 return ir_instruction_inttoerr_get_dep((IrInstructionIntToErr *) instruction, index);
2989 case IrInstructionIdErrToInt:
2990 return ir_instruction_errtoint_get_dep((IrInstructionErrToInt *) instruction, index);
2941 case IrInstructionIdCheckSwitchProngs:2991 case IrInstructionIdCheckSwitchProngs:
2942 return ir_instruction_checkswitchprongs_get_dep((IrInstructionCheckSwitchProngs *) instruction, index);2992 return ir_instruction_checkswitchprongs_get_dep((IrInstructionCheckSwitchProngs *) instruction, index);
2943 case IrInstructionIdTestType:2993 case IrInstructionIdTestType:
...@@ -6001,20 +6051,6 @@ static void eval_const_expr_implicit_cast(CastOp cast_op,...@@ -6001,20 +6051,6 @@ static void eval_const_expr_implicit_cast(CastOp cast_op,
6001 case CastOpBytesToSlice:6051 case CastOpBytesToSlice:
6002 // can't do it6052 // can't do it
6003 break;6053 break;
6004 case CastOpErrToInt:
6005 {
6006 uint64_t value;
6007 if (other_type->id == TypeTableEntryIdErrorUnion) {
6008 value = other_val->data.x_err_union.err ? other_val->data.x_err_union.err->value : 0;
6009 } else if (other_type->id == TypeTableEntryIdPureError) {
6010 value = other_val->data.x_pure_err->value;
6011 } else {
6012 zig_unreachable();
6013 }
6014 bignum_init_unsigned(&const_val->data.x_bignum, value);
6015 const_val->special = ConstValSpecialStatic;
6016 break;
6017 }
6018 case CastOpIntToFloat:6054 case CastOpIntToFloat:
6019 bignum_cast_to_float(&const_val->data.x_bignum, &other_val->data.x_bignum);6055 bignum_cast_to_float(&const_val->data.x_bignum, &other_val->data.x_bignum);
6020 const_val->special = ConstValSpecialStatic;6056 const_val->special = ConstValSpecialStatic;
...@@ -6707,6 +6743,87 @@ static IrInstruction *ir_analyze_number_to_literal(IrAnalyze *ira, IrInstruction...@@ -6707,6 +6743,87 @@ static IrInstruction *ir_analyze_number_to_literal(IrAnalyze *ira, IrInstruction
6707 return result;6743 return result;
6708}6744}
67096745
6746static IrInstruction *ir_analyze_int_to_err(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *target) {
6747 assert(target->value.type->id == TypeTableEntryIdInt);
6748 assert(!target->value.type->data.integral.is_signed);
6749
6750 if (instr_is_comptime(target)) {
6751 ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
6752 if (!val)
6753 return ira->codegen->invalid_instruction;
6754
6755 IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
6756 source_instr->source_node, ira->codegen->builtin_types.entry_pure_error);
6757
6758 uint64_t index = val->data.x_bignum.data.x_uint;
6759 if (index == 0 || index >= ira->codegen->error_decls.length) {
6760 ir_add_error(ira, source_instr,
6761 buf_sprintf("integer value %" PRIu64 " represents no error", index));
6762 return ira->codegen->invalid_instruction;
6763 }
6764
6765 AstNode *error_decl_node = ira->codegen->error_decls.at(index);
6766 result->value.data.x_pure_err = error_decl_node->data.error_value_decl.err;
6767 return result;
6768 }
6769
6770 IrInstruction *result = ir_build_int_to_err(&ira->new_irb, source_instr->scope, source_instr->source_node, target);
6771 result->value.type = ira->codegen->builtin_types.entry_pure_error;
6772 return result;
6773}
6774
6775static IrInstruction *ir_analyze_err_to_int(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *target,
6776 TypeTableEntry *wanted_type)
6777{
6778 assert(wanted_type->id == TypeTableEntryIdInt);
6779
6780 TypeTableEntry *err_type = target->value.type;
6781
6782 if (instr_is_comptime(target)) {
6783 ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
6784 if (!val)
6785 return ira->codegen->invalid_instruction;
6786
6787 IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
6788 source_instr->source_node, wanted_type);
6789
6790 ErrorTableEntry *err;
6791 if (err_type->id == TypeTableEntryIdErrorUnion) {
6792 err = val->data.x_err_union.err;
6793 } else if (err_type->id == TypeTableEntryIdPureError) {
6794 err = val->data.x_pure_err;
6795 } else {
6796 zig_unreachable();
6797 }
6798 result->value.type = wanted_type;
6799 uint64_t err_value = err ? err->value : 0;
6800 bignum_init_unsigned(&result->value.data.x_bignum, err_value);
6801
6802 if (!bignum_fits_in_bits(&result->value.data.x_bignum,
6803 wanted_type->data.integral.bit_count, wanted_type->data.integral.is_signed))
6804 {
6805 ir_add_error_node(ira, source_instr->source_node,
6806 buf_sprintf("error code '%s' does not fit in '%s'",
6807 buf_ptr(&err->name), buf_ptr(&wanted_type->name)));
6808 return ira->codegen->invalid_instruction;
6809 }
6810
6811 return result;
6812 }
6813
6814 BigNum bn;
6815 bignum_init_unsigned(&bn, ira->codegen->error_decls.length);
6816 if (!bignum_fits_in_bits(&bn, wanted_type->data.integral.bit_count, wanted_type->data.integral.is_signed)) {
6817 ir_add_error_node(ira, source_instr->source_node,
6818 buf_sprintf("too many error values to fit in '%s'", buf_ptr(&wanted_type->name)));
6819 return ira->codegen->invalid_instruction;
6820 }
6821
6822 IrInstruction *result = ir_build_err_to_int(&ira->new_irb, source_instr->scope, source_instr->source_node, target);
6823 result->value.type = wanted_type;
6824 return result;
6825}
6826
6710static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr,6827static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr,
6711 TypeTableEntry *wanted_type, IrInstruction *value)6828 TypeTableEntry *wanted_type, IrInstruction *value)
6712{6829{
...@@ -6781,7 +6898,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst...@@ -6781,7 +6898,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
6781 return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpFloatToInt, false);6898 return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpFloatToInt, false);
6782 }6899 }
67836900
6784 // explicit cast from array to slice6901 // explicit cast from [N]T to []const T
6785 if (is_slice(wanted_type) && actual_type->id == TypeTableEntryIdArray) {6902 if (is_slice(wanted_type) && actual_type->id == TypeTableEntryIdArray) {
6786 TypeTableEntry *ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;6903 TypeTableEntry *ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
6787 assert(ptr_type->id == TypeTableEntryIdPointer);6904 assert(ptr_type->id == TypeTableEntryIdPointer);
...@@ -6909,17 +7026,14 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst...@@ -6909,17 +7026,14 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
6909 if ((actual_type_is_void_err || actual_type_is_pure_err) &&7026 if ((actual_type_is_void_err || actual_type_is_pure_err) &&
6910 wanted_type->id == TypeTableEntryIdInt)7027 wanted_type->id == TypeTableEntryIdInt)
6911 {7028 {
6912 BigNum bn;7029 return ir_analyze_err_to_int(ira, source_instr, value, wanted_type);
6913 bignum_init_unsigned(&bn, ira->codegen->error_decls.length);7030 }
6914 if (bignum_fits_in_bits(&bn, wanted_type->data.integral.bit_count,7031
6915 wanted_type->data.integral.is_signed))7032 // explicit cast from integer to pure error
6916 {7033 if (wanted_type->id == TypeTableEntryIdPureError && actual_type->id == TypeTableEntryIdInt &&
6917 return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpErrToInt, false);7034 !actual_type->data.integral.is_signed)
6918 } else {7035 {
6919 ir_add_error_node(ira, source_instr->source_node,7036 return ir_analyze_int_to_err(ira, source_instr, value);
6920 buf_sprintf("too many error values to fit in '%s'", buf_ptr(&wanted_type->name)));
6921 return ira->codegen->invalid_instruction;
6922 }
6923 }7037 }
69247038
6925 // explicit cast from integer to enum type with no payload7039 // explicit cast from integer to enum type with no payload
...@@ -7843,7 +7957,7 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc...@@ -7843,7 +7957,7 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
7843 result_type = ira->codegen->builtin_types.entry_invalid;7957 result_type = ira->codegen->builtin_types.entry_invalid;
7844 }7958 }
78457959
7846 bool is_comptime_var = ir_get_var_is_comptime(var); 7960 bool is_comptime_var = ir_get_var_is_comptime(var);
78477961
7848 switch (result_type->id) {7962 switch (result_type->id) {
7849 case TypeTableEntryIdTypeDecl:7963 case TypeTableEntryIdTypeDecl:
...@@ -7852,6 +7966,7 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc...@@ -7852,6 +7966,7 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
7852 break; // handled above7966 break; // handled above
7853 case TypeTableEntryIdNumLitFloat:7967 case TypeTableEntryIdNumLitFloat:
7854 case TypeTableEntryIdNumLitInt:7968 case TypeTableEntryIdNumLitInt:
7969 case TypeTableEntryIdUndefLit:
7855 if (is_export || is_extern || (!var->src_is_const && !is_comptime_var)) {7970 if (is_export || is_extern || (!var->src_is_const && !is_comptime_var)) {
7856 ir_add_error_node(ira, source_node, buf_sprintf("unable to infer variable type"));7971 ir_add_error_node(ira, source_node, buf_sprintf("unable to infer variable type"));
7857 result_type = ira->codegen->builtin_types.entry_invalid;7972 result_type = ira->codegen->builtin_types.entry_invalid;
...@@ -7873,7 +7988,6 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc...@@ -7873,7 +7988,6 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
7873 result_type = ira->codegen->builtin_types.entry_invalid;7988 result_type = ira->codegen->builtin_types.entry_invalid;
7874 }7989 }
7875 break;7990 break;
7876 case TypeTableEntryIdUndefLit:
7877 case TypeTableEntryIdVoid:7991 case TypeTableEntryIdVoid:
7878 case TypeTableEntryIdBool:7992 case TypeTableEntryIdBool:
7879 case TypeTableEntryIdInt:7993 case TypeTableEntryIdInt:
...@@ -10765,6 +10879,8 @@ static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira...@@ -10765,6 +10879,8 @@ static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira
10765 TypeTableEntry *this_field_type = field->type_entry;10879 TypeTableEntry *this_field_type = field->type_entry;
1076610880
10767 IrInstruction *init_value = instruction->items[0]->other;10881 IrInstruction *init_value = instruction->items[0]->other;
10882 if (type_is_invalid(init_value->value.type))
10883 return ira->codegen->builtin_types.entry_invalid;
1076810884
10769 IrInstruction *casted_init_value = ir_implicit_cast(ira, init_value, this_field_type);10885 IrInstruction *casted_init_value = ir_implicit_cast(ira, init_value, this_field_type);
10770 if (casted_init_value == ira->codegen->invalid_instruction)10886 if (casted_init_value == ira->codegen->invalid_instruction)
...@@ -12311,6 +12427,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi...@@ -12311,6 +12427,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
12311 case IrInstructionIdIntToPtr:12427 case IrInstructionIdIntToPtr:
12312 case IrInstructionIdPtrToInt:12428 case IrInstructionIdPtrToInt:
12313 case IrInstructionIdIntToEnum:12429 case IrInstructionIdIntToEnum:
12430 case IrInstructionIdIntToErr:
12431 case IrInstructionIdErrToInt:
12314 case IrInstructionIdStructInit:12432 case IrInstructionIdStructInit:
12315 case IrInstructionIdStructFieldPtr:12433 case IrInstructionIdStructFieldPtr:
12316 case IrInstructionIdEnumFieldPtr:12434 case IrInstructionIdEnumFieldPtr:
...@@ -12650,6 +12768,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -12650,6 +12768,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
12650 case IrInstructionIdPtrToInt:12768 case IrInstructionIdPtrToInt:
12651 case IrInstructionIdIntToPtr:12769 case IrInstructionIdIntToPtr:
12652 case IrInstructionIdIntToEnum:12770 case IrInstructionIdIntToEnum:
12771 case IrInstructionIdIntToErr:
12772 case IrInstructionIdErrToInt:
12653 case IrInstructionIdTestType:12773 case IrInstructionIdTestType:
12654 case IrInstructionIdTypeName:12774 case IrInstructionIdTypeName:
12655 case IrInstructionIdCanImplicitCast:12775 case IrInstructionIdCanImplicitCast:
src/ir_print.cpp+16
...@@ -799,6 +799,16 @@ static void ir_print_int_to_enum(IrPrint *irp, IrInstructionIntToEnum *instructi...@@ -799,6 +799,16 @@ static void ir_print_int_to_enum(IrPrint *irp, IrInstructionIntToEnum *instructi
799 fprintf(irp->f, ")");799 fprintf(irp->f, ")");
800}800}
801801
802static void ir_print_int_to_err(IrPrint *irp, IrInstructionIntToErr *instruction) {
803 fprintf(irp->f, "inttoerr ");
804 ir_print_other_instruction(irp, instruction->target);
805}
806
807static void ir_print_err_to_int(IrPrint *irp, IrInstructionErrToInt *instruction) {
808 fprintf(irp->f, "errtoint ");
809 ir_print_other_instruction(irp, instruction->target);
810}
811
802static void ir_print_check_switch_prongs(IrPrint *irp, IrInstructionCheckSwitchProngs *instruction) {812static void ir_print_check_switch_prongs(IrPrint *irp, IrInstructionCheckSwitchProngs *instruction) {
803 fprintf(irp->f, "@checkSwitchProngs(");813 fprintf(irp->f, "@checkSwitchProngs(");
804 ir_print_other_instruction(irp, instruction->target_value);814 ir_print_other_instruction(irp, instruction->target_value);
...@@ -1117,6 +1127,12 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -1117,6 +1127,12 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1117 case IrInstructionIdIntToEnum:1127 case IrInstructionIdIntToEnum:
1118 ir_print_int_to_enum(irp, (IrInstructionIntToEnum *)instruction);1128 ir_print_int_to_enum(irp, (IrInstructionIntToEnum *)instruction);
1119 break;1129 break;
1130 case IrInstructionIdIntToErr:
1131 ir_print_int_to_err(irp, (IrInstructionIntToErr *)instruction);
1132 break;
1133 case IrInstructionIdErrToInt:
1134 ir_print_err_to_int(irp, (IrInstructionErrToInt *)instruction);
1135 break;
1120 case IrInstructionIdCheckSwitchProngs:1136 case IrInstructionIdCheckSwitchProngs:
1121 ir_print_check_switch_prongs(irp, (IrInstructionCheckSwitchProngs *)instruction);1137 ir_print_check_switch_prongs(irp, (IrInstructionCheckSwitchProngs *)instruction);
1122 break;1138 break;
std/build.zig+35-3
...@@ -3,8 +3,12 @@ const mem = @import("mem.zig");...@@ -3,8 +3,12 @@ const mem = @import("mem.zig");
3const debug = @import("debug.zig");3const debug = @import("debug.zig");
4const List = @import("list.zig").List;4const List = @import("list.zig").List;
5const Allocator = @import("mem.zig").Allocator;5const Allocator = @import("mem.zig").Allocator;
6const os = @import("os/index.zig");
7const StdIo = os.ChildProcess.StdIo;
8const Term = os.ChildProcess.Term;
69
7error ExtraArg;10error ExtraArg;
11error UncleanExit;
812
9pub const Builder = struct {13pub const Builder = struct {
10 zig_exe: []const u8,14 zig_exe: []const u8,
...@@ -33,9 +37,9 @@ pub const Builder = struct {...@@ -33,9 +37,9 @@ pub const Builder = struct {
33 return exe;37 return exe;
34 }38 }
3539
36 pub fn make(self: &Builder, args: []const []const u8) -> %void {40 pub fn make(self: &Builder, cli_args: []const []const u8) -> %void {
37 var verbose = false;41 var verbose = false;
38 for (args) |arg| {42 for (cli_args) |arg| {
39 if (mem.eql(u8, arg, "--verbose")) {43 if (mem.eql(u8, arg, "--verbose")) {
40 verbose = true;44 verbose = true;
41 } else {45 } else {
...@@ -44,7 +48,27 @@ pub const Builder = struct {...@@ -44,7 +48,27 @@ pub const Builder = struct {
44 }48 }
45 }49 }
46 for (self.exe_list.toSlice()) |exe| {50 for (self.exe_list.toSlice()) |exe| {
47 %%io.stderr.printf("TODO: invoke this command:\nzig build_exe {} --name {}\n", exe.root_src, exe.name);51 var zig_args = List([]const u8).init(self.allocator);
52 defer zig_args.deinit();
53
54 %return zig_args.append("build_exe"[0...]); // TODO issue #296
55 %return zig_args.append(exe.root_src);
56 %return zig_args.append("--name"[0...]); // TODO issue #296
57 %return zig_args.append(exe.name);
58
59 printInvocation(self.zig_exe, zig_args);
60 const TODO_env: []const []const u8 = undefined; // TODO
61 var child = %return os.ChildProcess.spawn(self.zig_exe, zig_args.toSliceConst(), TODO_env,
62 StdIo.Ignore, StdIo.Inherit, StdIo.Inherit);
63 const term = %return child.wait();
64 switch (term) {
65 Term.Clean => |code| {
66 if (code != 0) {
67 return error.UncleanExit;
68 }
69 },
70 else => return error.UncleanExit,
71 }
48 }72 }
49 }73 }
50};74};
...@@ -57,3 +81,11 @@ const Exe = struct {...@@ -57,3 +81,11 @@ const Exe = struct {
57fn handleErr(err: error) -> noreturn {81fn handleErr(err: error) -> noreturn {
58 debug.panic("error: {}\n", @errorName(err));82 debug.panic("error: {}\n", @errorName(err));
59}83}
84
85fn printInvocation(exe_name: []const u8, args: &const List([]const u8)) {
86 %%io.stderr.printf("{}", exe_name);
87 for (args.toSliceConst()) |arg| {
88 %%io.stderr.printf(" {}", arg);
89 }
90 %%io.stderr.printf("\n");
91}
std/io.zig+4-9
...@@ -13,22 +13,18 @@ const mem = @import("mem.zig");...@@ -13,22 +13,18 @@ const mem = @import("mem.zig");
13const Buffer0 = @import("cstr.zig").Buffer0;13const Buffer0 = @import("cstr.zig").Buffer0;
14const fmt = @import("fmt.zig");14const fmt = @import("fmt.zig");
1515
16pub const stdin_fileno = 0;
17pub const stdout_fileno = 1;
18pub const stderr_fileno = 2;
19
20pub var stdin = InStream {16pub var stdin = InStream {
21 .fd = stdin_fileno,17 .fd = system.STDIN_FILENO,
22};18};
2319
24pub var stdout = OutStream {20pub var stdout = OutStream {
25 .fd = stdout_fileno,21 .fd = system.STDOUT_FILENO,
26 .buffer = undefined,22 .buffer = undefined,
27 .index = 0,23 .index = 0,
28};24};
2925
30pub var stderr = OutStream {26pub var stderr = OutStream {
31 .fd = stderr_fileno,27 .fd = system.STDERR_FILENO,
32 .buffer = undefined,28 .buffer = undefined,
33 .index = 0,29 .index = 0,
34};30};
...@@ -234,7 +230,6 @@ pub const InStream = struct {...@@ -234,7 +230,6 @@ pub const InStream = struct {
234 if (read_err > 0) {230 if (read_err > 0) {
235 switch (read_err) {231 switch (read_err) {
236 errno.EINTR => continue,232 errno.EINTR => continue,
237
238 errno.EINVAL => unreachable,233 errno.EINVAL => unreachable,
239 errno.EFAULT => unreachable,234 errno.EFAULT => unreachable,
240 errno.EBADF => return error.BadFd,235 errno.EBADF => return error.BadFd,
...@@ -247,7 +242,7 @@ pub const InStream = struct {...@@ -247,7 +242,7 @@ pub const InStream = struct {
247 }242 }
248 return index;243 return index;
249 },244 },
250 else => @compileError("unsupported OS"),245 else => @compileError("Unsupported OS"),
251 }246 }
252 }247 }
253248
std/os/darwin.zig+4
...@@ -6,6 +6,10 @@ const arch = switch (@compileVar("arch")) {...@@ -6,6 +6,10 @@ const arch = switch (@compileVar("arch")) {
66
7const errno = @import("errno.zig");7const errno = @import("errno.zig");
88
9pub const STDIN_FILENO = 0;
10pub const STDOUT_FILENO = 1;
11pub const STDERR_FILENO = 2;
12
9pub const O_LARGEFILE = 0x0000;13pub const O_LARGEFILE = 0x0000;
10pub const O_RDONLY = 0x0000;14pub const O_RDONLY = 0x0000;
1115
std/os/index.zig+343
...@@ -7,12 +7,26 @@ pub const posix = switch(@compileVar("os")) {...@@ -7,12 +7,26 @@ pub const posix = switch(@compileVar("os")) {
7 Os.windows => windows,7 Os.windows => windows,
8 else => @compileError("Unsupported OS"),8 else => @compileError("Unsupported OS"),
9};9};
10const debug = @import("../debug.zig");
11const assert = debug.assert;
1012
11const errno = @import("errno.zig");13const errno = @import("errno.zig");
12const linking_libc = @import("../target.zig").linking_libc;14const linking_libc = @import("../target.zig").linking_libc;
13const c = @import("../c/index.zig");15const c = @import("../c/index.zig");
1416
17const mem = @import("../mem.zig");
18const Allocator = mem.Allocator;
19
20const io = @import("../io.zig");
21
15error Unexpected;22error Unexpected;
23error SysResources;
24error AccessDenied;
25error InvalidExe;
26error FileSystem;
27error IsDir;
28error FileNotFound;
29error FileBusy;
1630
17/// Fills `buf` with random bytes. If linking against libc, this calls the31/// Fills `buf` with random bytes. If linking against libc, this calls the
18/// appropriate OS-specific library call. Otherwise it uses the zig standard32/// appropriate OS-specific library call. Otherwise it uses the zig standard
...@@ -76,3 +90,332 @@ pub coldcc fn abort() -> noreturn {...@@ -76,3 +90,332 @@ pub coldcc fn abort() -> noreturn {
76 else => @compileError("Unsupported OS"),90 else => @compileError("Unsupported OS"),
77 }91 }
78}92}
93
94fn makePipe() -> %[2]i32 {
95 var fds: [2]i32 = undefined;
96 const err = posix.getErrno(posix.pipe(&fds));
97 if (err > 0) {
98 return switch (err) {
99 errno.EMFILE, errno.ENFILE => error.SysResources,
100 else => error.Unexpected,
101 }
102 }
103 return fds;
104}
105
106fn destroyPipe(pipe: &const [2]i32) {
107 closeNoIntr((*pipe)[0]);
108 closeNoIntr((*pipe)[1]);
109}
110
111fn closeNoIntr(fd: i32) {
112 while (true) {
113 const err = posix.getErrno(posix.close(fd));
114 if (err == errno.EINTR) {
115 continue;
116 } else {
117 return;
118 }
119 }
120}
121
122fn openNoIntr(path: []const u8, flags: usize, perm: usize) -> %i32 {
123 while (true) {
124 const result = posix.open(path, flags, perm);
125 const err = posix.getErrno(result);
126 if (err > 0) {
127 return switch (err) {
128 errno.EINTR => continue,
129
130 errno.EFAULT => unreachable,
131 errno.EINVAL => unreachable,
132 errno.EACCES => error.BadPerm,
133 errno.EFBIG, errno.EOVERFLOW => error.FileTooBig,
134 errno.EISDIR => error.IsDir,
135 errno.ELOOP => error.SymLinkLoop,
136 errno.EMFILE => error.ProcessFdQuotaExceeded,
137 errno.ENAMETOOLONG => error.NameTooLong,
138 errno.ENFILE => error.SystemFdQuotaExceeded,
139 errno.ENODEV => error.NoDevice,
140 errno.ENOENT => error.PathNotFound,
141 errno.ENOMEM => error.NoMem,
142 errno.ENOSPC => error.NoSpaceLeft,
143 errno.ENOTDIR => error.NotDir,
144 errno.EPERM => error.BadPerm,
145 else => error.Unexpected,
146 }
147 }
148 return i32(result);
149 }
150}
151
152const ErrInt = @intType(false, @sizeOf(error) * 8);
153fn writeIntFd(fd: i32, value: ErrInt) -> %void {
154 var bytes: [@sizeOf(ErrInt)]u8 = undefined;
155 mem.writeInt(bytes[0...], value, true);
156
157 var index: usize = 0;
158 while (index < bytes.len) {
159 const amt_written = posix.write(fd, &bytes[index], bytes.len - index);
160 const err = posix.getErrno(amt_written);
161 if (err > 0) {
162 switch (err) {
163 errno.EINTR => continue,
164 errno.EINVAL => unreachable,
165 else => return error.SysResources,
166 }
167 }
168 index += amt_written;
169 }
170}
171
172fn readIntFd(fd: i32) -> %ErrInt {
173 var bytes: [@sizeOf(ErrInt)]u8 = undefined;
174
175 var index: usize = 0;
176 while (index < bytes.len) {
177 const amt_written = posix.read(fd, &bytes[index], bytes.len - index);
178 const err = posix.getErrno(amt_written);
179 if (err > 0) {
180 switch (err) {
181 errno.EINTR => continue,
182 errno.EINVAL => unreachable,
183 else => return error.SysResources,
184 }
185 }
186 index += amt_written;
187 }
188
189 return mem.readInt(bytes[0...], ErrInt, true);
190}
191
192// Child of fork calls this to report an error to the fork parent.
193// Then the child exits.
194fn forkChildErrReport(fd: i32, err: error) -> noreturn {
195 _ = writeIntFd(fd, ErrInt(err));
196 posix.exit(1);
197}
198
199fn dup2NoIntr(old_fd: i32, new_fd: i32) -> %void {
200 while (true) {
201 const err = posix.getErrno(posix.dup2(old_fd, new_fd));
202 if (err > 0) {
203 return switch (err) {
204 errno.EBUSY, errno.EINTR => continue,
205 errno.EMFILE => error.SysResources,
206 errno.EINVAL => unreachable,
207 else => error.Unexpected,
208 };
209 }
210 return;
211 }
212}
213
214pub const ChildProcess = struct {
215 pid: i32,
216 err_pipe: [2]i32,
217
218 stdin: ?io.OutStream,
219 stdout: ?io.InStream,
220 stderr: ?io.InStream,
221
222 pub const Term = enum {
223 Clean: i32,
224 Signal: i32,
225 Stopped: i32,
226 Unknown: i32,
227 };
228
229 pub const StdIo = enum {
230 Inherit,
231 Ignore,
232 Pipe,
233 Close,
234 };
235
236 pub fn spawn(exe_path: []const u8, args: []const []const u8, env: []const []const u8,
237 stdin: StdIo, stdout: StdIo, stderr: StdIo) -> %ChildProcess
238 {
239 switch (@compileVar("os")) {
240 Os.linux, Os.macosx, Os.ios, Os.darwin => {
241 return spawnPosix(exe_path, args, env, stdin, stdout, stderr);
242 },
243 else => @compileError("Unsupported OS"),
244 }
245 }
246
247 pub fn wait(self: &ChildProcess) -> %Term {
248 defer {
249 closeNoIntr(self.err_pipe[0]);
250 closeNoIntr(self.err_pipe[1]);
251 };
252
253 var status: i32 = undefined;
254 while (true) {
255 const err = posix.getErrno(posix.waitpid(self.pid, &status, 0));
256 if (err > 0) {
257 switch (err) {
258 errno.EINVAL, errno.ECHILD => unreachable,
259 errno.EINTR => continue,
260 else => {
261 if (const *stdin ?= self.stdin) { stdin.close(); }
262 if (const *stdout ?= self.stdin) { stdout.close(); }
263 if (const *stderr ?= self.stdin) { stderr.close(); }
264 return error.Unexpected;
265 },
266 }
267 }
268 break;
269 }
270
271 if (const *stdin ?= self.stdin) { stdin.close(); }
272 if (const *stdout ?= self.stdin) { stdout.close(); }
273 if (const *stderr ?= self.stdin) { stderr.close(); }
274
275 // Write @maxValue(ErrInt) to the write end of the err_pipe. This is after
276 // waitpid, so this write is guaranteed to be after the child
277 // pid potentially wrote an error. This way we can do a blocking
278 // read on the error pipe and either get @maxValue(ErrInt) (no error) or
279 // an error code.
280 %return writeIntFd(self.err_pipe[1], @maxValue(ErrInt));
281 const err_int = %return readIntFd(self.err_pipe[0]);
282 // Here we potentially return the fork child's error
283 // from the parent pid.
284 if (err_int != @maxValue(ErrInt)) {
285 return error(err_int);
286 }
287
288 return statusToTerm(status);
289 }
290
291 fn statusToTerm(status: i32) -> Term {
292 return if (posix.WIFEXITED(status)) {
293 Term.Clean { posix.WEXITSTATUS(status) }
294 } else if (posix.WIFSIGNALED(status)) {
295 Term.Signal { posix.WTERMSIG(status) }
296 } else if (posix.WIFSTOPPED(status)) {
297 Term.Stopped { posix.WSTOPSIG(status) }
298 } else {
299 Term.Unknown { status }
300 };
301 }
302
303 fn spawnPosix(exe_path: []const u8, args: []const []const u8, env: []const []const u8,
304 stdin: StdIo, stdout: StdIo, stderr: StdIo) -> %ChildProcess
305 {
306 // TODO issue #295
307 //const stdin_pipe = if (stdin == StdIo.Pipe) %return makePipe() else undefined;
308 var stdin_pipe: [2]i32 = undefined;
309 if (stdin == StdIo.Pipe)
310 stdin_pipe = %return makePipe();
311 %defer if (stdin == StdIo.Pipe) { destroyPipe(stdin_pipe); };
312
313 // TODO issue #295
314 //const stdout_pipe = if (stdout == StdIo.Pipe) %return makePipe() else undefined;
315 var stdout_pipe: [2]i32 = undefined;
316 if (stdout == StdIo.Pipe)
317 stdout_pipe = %return makePipe();
318 %defer if (stdout == StdIo.Pipe) { destroyPipe(stdout_pipe); };
319
320 // TODO issue #295
321 //const stderr_pipe = if (stderr == StdIo.Pipe) %return makePipe() else undefined;
322 var stderr_pipe: [2]i32 = undefined;
323 if (stderr == StdIo.Pipe)
324 stderr_pipe = %return makePipe();
325 %defer if (stderr == StdIo.Pipe) { destroyPipe(stderr_pipe); };
326
327 const any_ignore = (stdin == StdIo.Ignore or stdout == StdIo.Ignore or stderr == StdIo.Ignore);
328 // TODO issue #295
329 //const dev_null_fd = if (any_ignore) {
330 // %return openNoIntr("/dev/null", posix.O_RDWR, 0)
331 //} else {
332 // undefined
333 //};
334 var dev_null_fd: i32 = undefined;
335 if (any_ignore)
336 dev_null_fd = %return openNoIntr("/dev/null", posix.O_RDWR, 0);
337
338 // This pipe is used to communicate errors between the time of fork
339 // and execve from the child process to the parent process.
340 const err_pipe = %return makePipe();
341 %defer destroyPipe(err_pipe);
342
343 const pid = posix.fork();
344 const pid_err = linux.getErrno(pid);
345 if (pid_err > 0) {
346 return switch (pid_err) {
347 errno.EAGAIN, errno.ENOMEM, errno.ENOSYS => error.SysResources,
348 else => error.Unexpected,
349 };
350 }
351 if (pid == 0) {
352 // we are the child
353 setUpChildIo(stdin, stdin_pipe[0], posix.STDIN_FILENO, dev_null_fd) %%
354 |err| forkChildErrReport(err_pipe[1], err);
355 setUpChildIo(stdout, stdout_pipe[1], posix.STDOUT_FILENO, dev_null_fd) %%
356 |err| forkChildErrReport(err_pipe[1], err);
357 setUpChildIo(stderr, stderr_pipe[1], posix.STDERR_FILENO, dev_null_fd) %%
358 |err| forkChildErrReport(err_pipe[1], err);
359
360 const err = posix.getErrno(posix.execve(exe_path, args, env));
361 assert(err > 0);
362 forkChildErrReport(err_pipe[1], switch (err) {
363 errno.EFAULT => unreachable,
364 errno.E2BIG, errno.EMFILE, errno.ENAMETOOLONG, errno.ENFILE, errno.ENOMEM => error.SysResources,
365 errno.EACCES, errno.EPERM => error.AccessDenied,
366 errno.EINVAL, errno.ENOEXEC => error.InvalidExe,
367 errno.EIO, errno.ELOOP => error.FileSystem,
368 errno.EISDIR => error.IsDir,
369 errno.ENOENT, errno.ENOTDIR => error.FileNotFound,
370 errno.ETXTBSY => error.FileBusy,
371 else => error.Unexpected,
372 });
373 }
374
375 // we are the parent
376 if (stdin == StdIo.Pipe) { closeNoIntr(stdin_pipe[0]); }
377 if (stdout == StdIo.Pipe) { closeNoIntr(stdout_pipe[1]); }
378 if (stderr == StdIo.Pipe) { closeNoIntr(stderr_pipe[1]); }
379 if (any_ignore) { closeNoIntr(dev_null_fd); }
380
381 return ChildProcess {
382 .pid = i32(pid),
383 .err_pipe = err_pipe,
384
385 .stdin = if (stdin == StdIo.Pipe) {
386 io.OutStream {
387 .fd = stdin_pipe[1],
388 }
389 } else {
390 null
391 },
392 .stdout = if (stdout == StdIo.Pipe) {
393 io.InStream {
394 .fd = stdout_pipe[0],
395 .buffer = undefined,
396 .index = 0,
397 }
398 } else {
399 null
400 },
401 .stderr = if (stderr == StdIo.Pipe) {
402 io.InStream {
403 .fd = stderr_pipe[0],
404 .buffer = undefined,
405 .index = 0,
406 }
407 } else {
408 null
409 },
410 };
411 }
412
413 fn setUpChildIo(stdio: StdIo, pipe_fd: i32, std_fileno: i32, dev_null_fd: i32) -> %void {
414 switch (stdio) {
415 StdIo.Pipe => %return dup2NoIntr(pipe_fd, std_fileno),
416 StdIo.Close => closeNoIntr(std_fileno),
417 StdIo.Inherit => {},
418 StdIo.Ignore => %return dup2NoIntr(dev_null_fd, std_fileno),
419 }
420 }
421};
std/os/linux.zig+72-2
...@@ -5,6 +5,10 @@ const arch = switch (@compileVar("arch")) {...@@ -5,6 +5,10 @@ const arch = switch (@compileVar("arch")) {
5};5};
6const errno = @import("errno.zig");6const errno = @import("errno.zig");
77
8pub const STDIN_FILENO = 0;
9pub const STDOUT_FILENO = 1;
10pub const STDERR_FILENO = 2;
11
8pub const PROT_NONE = 0;12pub const PROT_NONE = 0;
9pub const PROT_READ = 1;13pub const PROT_READ = 1;
10pub const PROT_WRITE = 2;14pub const PROT_WRITE = 2;
...@@ -237,12 +241,66 @@ pub const AF_NFC = PF_NFC;...@@ -237,12 +241,66 @@ pub const AF_NFC = PF_NFC;
237pub const AF_VSOCK = PF_VSOCK;241pub const AF_VSOCK = PF_VSOCK;
238pub const AF_MAX = PF_MAX;242pub const AF_MAX = PF_MAX;
239243
244
245fn unsigned(s: i32) -> u32 { *@ptrcast(&u32, &s) }
246fn signed(s: u32) -> i32 { *@ptrcast(&i32, &s) }
247pub fn WEXITSTATUS(s: i32) -> i32 { signed((unsigned(s) & 0xff00) >> 8) }
248pub fn WTERMSIG(s: i32) -> i32 { signed(unsigned(s) & 0x7f) }
249pub fn WSTOPSIG(s: i32) -> i32 { WEXITSTATUS(s) }
250pub fn WIFEXITED(s: i32) -> bool { WTERMSIG(s) == 0 }
251pub fn WIFSTOPPED(s: i32) -> bool { (u16)(((unsigned(s)&0xffff)*%0x10001)>>8) > 0x7f00 }
252pub fn WIFSIGNALED(s: i32) -> bool { (unsigned(s)&0xffff)-%1 < 0xff }
253
240/// Get the errno from a syscall return value, or 0 for no error.254/// Get the errno from a syscall return value, or 0 for no error.
241pub fn getErrno(r: usize) -> usize {255pub fn getErrno(r: usize) -> usize {
242 const signed_r = *@ptrcast(&isize, &r);256 const signed_r = *@ptrcast(&isize, &r);
243 if (signed_r > -4096 and signed_r < 0) usize(-signed_r) else 0257 if (signed_r > -4096 and signed_r < 0) usize(-signed_r) else 0
244}258}
245259
260pub fn dup2(old: i32, new: i32) -> usize {
261 arch.syscall2(arch.SYS_dup2, usize(old), usize(new))
262}
263
264pub fn execve_c(path: &const u8, argv: &const ?&const u8, envp: &const ?&const u8) -> usize {
265 arch.syscall3(arch.SYS_execve, path, argv, envp)
266}
267
268/// This function must allocate memory to add a null terminating bytes on path, each arg,
269/// and each environment variable line, as well as a null pointer after the arg list and
270/// environment variable list. We allocate stack memory since the process is about to get
271/// wiped anyway.
272pub fn execve(path: []const u8, argv: []const []const u8, envp: []const []const u8) -> usize {
273 const path_buf = @alloca(u8, path.len + 1);
274 @memcpy(&path_buf[0], &path[0], path.len);
275 path_buf[path.len] = 0;
276
277 const argv_buf = @alloca([]const ?&const u8, argv.len + 1);
278 for (argv) |arg, i| {
279 const arg_buf = @alloca(u8, arg.len + 1);
280 @memcpy(&arg_buf[0], &arg[0], arg.len);
281 arg_buf[arg.len] = 0;
282
283 argv[i] = arg_buf;
284 }
285 argv_buf[argv.len] = null;
286
287 const envp_buf = @alloca([]const ?&const u8, envp.len + 1);
288 for (envp) |env, i| {
289 const env_buf = @alloca(u8, env.len + 1);
290 @memcpy(&env_buf[0], &env[0], env.len);
291 env_buf[env.len] = 0;
292
293 envp[i] = env_buf;
294 }
295 envp_buf[envp.len] = null;
296
297 return execve_c(path_buf.ptr, argv_buf.ptr, envp_buf.ptr);
298}
299
300pub fn fork() -> usize {
301 arch.syscall0(arch.SYS_fork)
302}
303
246pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: usize, fd: i32, offset: usize)304pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: usize, fd: i32, offset: usize)
247 -> usize305 -> usize
248{306{
...@@ -261,6 +319,14 @@ pub fn pread(fd: i32, buf: &u8, count: usize, offset: usize) -> usize {...@@ -261,6 +319,14 @@ pub fn pread(fd: i32, buf: &u8, count: usize, offset: usize) -> usize {
261 arch.syscall4(arch.SYS_pread, usize(fd), usize(buf), count, offset)319 arch.syscall4(arch.SYS_pread, usize(fd), usize(buf), count, offset)
262}320}
263321
322pub fn pipe(fd: &[2]i32) -> usize {
323 pipe2(fd, 0)
324}
325
326pub fn pipe2(fd: &[2]i32, flags: usize) -> usize {
327 arch.syscall2(arch.SYS_pipe2, usize(fd), flags)
328}
329
264pub fn write(fd: i32, buf: &const u8, count: usize) -> usize {330pub fn write(fd: i32, buf: &const u8, count: usize) -> usize {
265 arch.syscall3(arch.SYS_write, usize(fd), usize(buf), count)331 arch.syscall3(arch.SYS_write, usize(fd), usize(buf), count)
266}332}
...@@ -319,8 +385,12 @@ pub fn getrandom(buf: &u8, count: usize, flags: u32) -> usize {...@@ -319,8 +385,12 @@ pub fn getrandom(buf: &u8, count: usize, flags: u32) -> usize {
319 arch.syscall3(arch.SYS_getrandom, usize(buf), count, usize(flags))385 arch.syscall3(arch.SYS_getrandom, usize(buf), count, usize(flags))
320}386}
321387
322pub fn kill(pid: i32, sig: i32) -> i32 {388pub fn kill(pid: i32, sig: i32) -> usize {
323 i32(arch.syscall2(arch.SYS_kill, usize(pid), usize(sig)))389 arch.syscall2(arch.SYS_kill, usize(pid), usize(sig))
390}
391
392pub fn waitpid(pid: i32, status: &i32, options: i32) -> usize {
393 arch.syscall4(arch.SYS_wait4, usize(pid), usize(status), usize(options), 0)
324}394}
325395
326const NSIG = 65;396const NSIG = 65;
test/cases/cast.zig+11
...@@ -30,3 +30,14 @@ test "implicitly cast a pointer to a const pointer of it" {...@@ -30,3 +30,14 @@ test "implicitly cast a pointer to a const pointer of it" {
30fn funcWithConstPtrPtr(x: &const &i32) {30fn funcWithConstPtrPtr(x: &const &i32) {
31 **x += 1;31 **x += 1;
32}32}
33
34error ItBroke;
35test "explicit cast from integer to error type" {
36 testCastIntToErr(error.ItBroke);
37 comptime testCastIntToErr(error.ItBroke);
38}
39fn testCastIntToErr(err: error) {
40 const x = usize(err);
41 const y = error(x);
42 assert(error.ItBroke == y);
43}
test/run_tests.cpp+28
...@@ -1758,6 +1758,13 @@ export fn foo() {...@@ -1758,6 +1758,13 @@ export fn foo() {
1758}1758}
1759 )SOURCE", 1, ".tmp_source.zig:3:5: error: unable to infer variable type");1759 )SOURCE", 1, ".tmp_source.zig:3:5: error: unable to infer variable type");
17601760
1761 add_compile_fail_case("undefined literal on a non-comptime var", R"SOURCE(
1762export fn foo() {
1763 var i = undefined;
1764 i = i32(1);
1765}
1766 )SOURCE", 1, ".tmp_source.zig:3:5: error: unable to infer variable type");
1767
1761 add_compile_fail_case("dereference an array", R"SOURCE(1768 add_compile_fail_case("dereference an array", R"SOURCE(
1762var s_buffer: [10]u8 = undefined;1769var s_buffer: [10]u8 = undefined;
1763pub fn pass(in: []u8) -> []u8 {1770pub fn pass(in: []u8) -> []u8 {
...@@ -1818,6 +1825,15 @@ export fn entry(a: &i32) -> usize {...@@ -1818,6 +1825,15 @@ export fn entry(a: &i32) -> usize {
1818 return @ptrcast(usize, a);1825 return @ptrcast(usize, a);
1819}1826}
1820 )SOURCE", 1, ".tmp_source.zig:3:21: error: expected pointer, found 'usize'");1827 )SOURCE", 1, ".tmp_source.zig:3:21: error: expected pointer, found 'usize'");
1828
1829 add_compile_fail_case("too many error values to cast to small integer", R"SOURCE(
1830error A; error B; error C; error D; error E; error F; error G; error H;
1831const u2 = @intType(false, 2);
1832fn foo(e: error) -> u2 {
1833 return u2(e);
1834}
1835export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
1836 )SOURCE", 1, ".tmp_source.zig:5:14: error: too many error values to fit in 'u2'");
1821}1837}
18221838
1823//////////////////////////////////////////////////////////////////////////////1839//////////////////////////////////////////////////////////////////////////////
...@@ -2043,6 +2059,18 @@ fn bar() -> %void {...@@ -2043,6 +2059,18 @@ fn bar() -> %void {
2043}2059}
2044 )SOURCE");2060 )SOURCE");
20452061
2062 add_debug_safety_case("cast integer to error and no code matches", R"SOURCE(
2063pub fn panic(message: []const u8) -> noreturn {
2064 @breakpoint();
2065 while (true) {}
2066}
2067pub fn main(args: [][]u8) -> %void {
2068 _ = bar(9999);
2069}
2070fn bar(x: u32) -> error {
2071 return error(x);
2072}
2073 )SOURCE");
2046}2074}
20472075
2048//////////////////////////////////////////////////////////////////////////////2076//////////////////////////////////////////////////////////////////////////////