From 0839ed1f945dbbe3ad1f780a5334ad16ad12fd5e Mon Sep 17 00:00:00 2001 From: kristopher tate Date: Mon, 27 Aug 2018 01:22:50 +0900 Subject: src/ir.cpp: check return value of `const_ptr_pointee` to protect against dereferencing null pointers; --- src/ir.cpp | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 5bf39ee691..48547298ae 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -10982,6 +10982,7 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar) { ConstExprValue *pointee = const_ptr_pointee(ira->codegen, &ptr->value); + if (!pointee) return ira->codegen->invalid_instruction; if (pointee->special != ConstValSpecialRuntime) { IrInstruction *result = ir_create_const(&ira->new_irb, source_instruction->scope, source_instruction->source_node, child_type); @@ -13655,6 +13656,7 @@ static TypeTableEntry *ir_analyze_dereference(IrAnalyze *ira, IrInstructionUnOp return ira->codegen->builtin_types.entry_invalid; ConstExprValue *pointee = const_ptr_pointee(ira->codegen, comptime_value); + if (!pointee) return ira->codegen->builtin_types.entry_invalid; if (pointee->type == child_type) { ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base); copy_const_val(out_val, pointee, value->value.data.x_ptr.mut == ConstPtrMutComptimeConst); @@ -14058,6 +14060,7 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc ptr_type = ptr_type->data.pointer.child_type; if (orig_array_ptr_val->special != ConstValSpecialRuntime) { orig_array_ptr_val = const_ptr_pointee(ira->codegen, orig_array_ptr_val); + if (!orig_array_ptr_val) return ira->codegen->builtin_types.entry_invalid; } } if (array_type->data.array.len == 0) { @@ -14099,6 +14102,7 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc if (!ptr_val) return ira->codegen->builtin_types.entry_invalid; ConstExprValue *args_val = const_ptr_pointee(ira->codegen, ptr_val); + if (!args_val) return ira->codegen->builtin_types.entry_invalid; size_t start = args_val->data.x_arg_tuple.start_index; size_t end = args_val->data.x_arg_tuple.end_index; uint64_t elem_index_val; @@ -14380,6 +14384,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_ if (ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) { ConstExprValue *struct_val = const_ptr_pointee(ira->codegen, ptr_val); + if (!struct_val) return ira->codegen->invalid_instruction; if (type_is_invalid(struct_val->type)) return ira->codegen->invalid_instruction; ConstExprValue *field_val = &struct_val->data.x_struct.fields[field->src_index]; @@ -14422,6 +14427,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_ if (ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) { ConstExprValue *union_val = const_ptr_pointee(ira->codegen, ptr_val); + if (!union_val) return ira->codegen->invalid_instruction; if (type_is_invalid(union_val->type)) return ira->codegen->invalid_instruction; @@ -14618,6 +14624,7 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru assert(container_ptr->value.type->id == TypeTableEntryIdPointer); ConstExprValue *child_val = const_ptr_pointee(ira->codegen, container_ptr_val); + if (!child_val) return ira->codegen->builtin_types.entry_invalid; if (buf_eql_str(field_name, "len")) { ConstExprValue *len_val = create_const_vals(1); @@ -14642,6 +14649,7 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru assert(container_ptr->value.type->id == TypeTableEntryIdPointer); ConstExprValue *child_val = const_ptr_pointee(ira->codegen, container_ptr_val); + if (!child_val) return ira->codegen->builtin_types.entry_invalid; TypeTableEntry *child_type = child_val->data.x_type; if (type_is_invalid(child_type)) { @@ -14910,6 +14918,7 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru return ira->codegen->builtin_types.entry_invalid; ConstExprValue *namespace_val = const_ptr_pointee(ira->codegen, container_ptr_val); + if (!namespace_val) return ira->codegen->builtin_types.entry_invalid; assert(namespace_val->special == ConstValSpecialStatic); ImportTableEntry *namespace_import = namespace_val->data.x_import; @@ -14986,6 +14995,7 @@ static TypeTableEntry *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstru if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar) { if (instr_is_comptime(casted_value)) { ConstExprValue *dest_val = const_ptr_pointee(ira->codegen, &ptr->value); + if (!dest_val) return ira->codegen->builtin_types.entry_invalid; if (dest_val->special != ConstValSpecialRuntime) { *dest_val = casted_value->value; if (!ira->new_irb.current_basic_block->must_be_comptime_source_instr) { @@ -14997,6 +15007,7 @@ static TypeTableEntry *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstru ir_add_error(ira, &store_ptr_instruction->base, buf_sprintf("cannot store runtime value in compile time variable")); ConstExprValue *dest_val = const_ptr_pointee(ira->codegen, &ptr->value); + if (!dest_val) return ira->codegen->builtin_types.entry_invalid; dest_val->type = ira->codegen->builtin_types.entry_invalid; return ira->codegen->builtin_types.entry_invalid; @@ -15850,7 +15861,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira, ConstExprValue *pointee_val = nullptr; if (instr_is_comptime(target_value_ptr)) { pointee_val = const_ptr_pointee(ira->codegen, &target_value_ptr->value); - if (pointee_val->special == ConstValSpecialRuntime) + if (pointee_val && pointee_val->special == ConstValSpecialRuntime) pointee_val = nullptr; } if ((err = ensure_complete_type(ira->codegen, target_type))) @@ -15981,6 +15992,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_var(IrAnalyze *ira, IrInstr return ira->codegen->builtin_types.entry_invalid; ConstExprValue *pointee_val = const_ptr_pointee(ira->codegen, target_val_ptr); + if (!pointee_val) return ira->codegen->builtin_types.entry_invalid; ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); out_val->data.x_ptr.special = ConstPtrSpecialRef; out_val->data.x_ptr.mut = target_val_ptr->data.x_ptr.mut; @@ -18732,11 +18744,14 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio TypeTableEntry *child_array_type = array_type->data.pointer.child_type; assert(child_array_type->id == TypeTableEntryIdArray); parent_ptr = const_ptr_pointee(ira->codegen, &ptr_ptr->value); + if (!parent_ptr) return ira->codegen->builtin_types.entry_invalid; array_val = const_ptr_pointee(ira->codegen, parent_ptr); + if (!array_val) return ira->codegen->builtin_types.entry_invalid; rel_end = child_array_type->data.array.len; abs_offset = 0; } else { array_val = const_ptr_pointee(ira->codegen, &ptr_ptr->value); + if (!array_val) return ira->codegen->builtin_types.entry_invalid; rel_end = array_type->data.array.len; parent_ptr = nullptr; abs_offset = 0; @@ -18744,6 +18759,7 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio } else if (array_type->id == TypeTableEntryIdPointer) { assert(array_type->data.pointer.ptr_len == PtrLenUnknown); parent_ptr = const_ptr_pointee(ira->codegen, &ptr_ptr->value); + if (!parent_ptr) return ira->codegen->builtin_types.entry_invalid; if (parent_ptr->special == ConstValSpecialUndef) { array_val = nullptr; abs_offset = 0; @@ -18775,6 +18791,7 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio } } else if (is_slice(array_type)) { ConstExprValue *slice_ptr = const_ptr_pointee(ira->codegen, &ptr_ptr->value); + if (!slice_ptr) return ira->codegen->builtin_types.entry_invalid; parent_ptr = &slice_ptr->data.x_struct.fields[slice_ptr_index]; ConstExprValue *len_val = &slice_ptr->data.x_struct.fields[slice_len_index]; @@ -19175,6 +19192,7 @@ static TypeTableEntry *ir_analyze_instruction_overflow_op(IrAnalyze *ira, IrInst BigInt *op1_bigint = &casted_op1->value.data.x_bigint; BigInt *op2_bigint = &casted_op2->value.data.x_bigint; ConstExprValue *pointee_val = const_ptr_pointee(ira->codegen, &casted_result_ptr->value); + if (!pointee_val) return ira->codegen->builtin_types.entry_invalid; BigInt *dest_bigint = &pointee_val->data.x_bigint; switch (instruction->op) { case IrOverflowOpAdd: @@ -19275,6 +19293,7 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira, if (!ptr_val) return ira->codegen->builtin_types.entry_invalid; ConstExprValue *err_union_val = const_ptr_pointee(ira->codegen, ptr_val); + if (!err_union_val) return ira->codegen->builtin_types.entry_invalid; if (err_union_val->special != ConstValSpecialRuntime) { ErrorTableEntry *err = err_union_val->data.x_err_union.err; assert(err); @@ -19323,6 +19342,7 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira, if (!ptr_val) return ira->codegen->builtin_types.entry_invalid; ConstExprValue *err_union_val = const_ptr_pointee(ira->codegen, ptr_val); + if (!err_union_val) return ira->codegen->builtin_types.entry_invalid; if (err_union_val->special != ConstValSpecialRuntime) { ErrorTableEntry *err = err_union_val->data.x_err_union.err; if (err != nullptr) { -- cgit v1.2.3 From 6a3fad1d596a59846d072a005f77f6c59da09824 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 26 Aug 2018 13:04:58 -0400 Subject: Revert "src/ir.cpp: check return value of `const_ptr_pointee` to protect against dereferencing null pointers;" This reverts commit 0839ed1f945dbbe3ad1f780a5334ad16ad12fd5e. I realized too late there is a better fix. See PR #1419 --- src/ir.cpp | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 48547298ae..5bf39ee691 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -10982,7 +10982,6 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar) { ConstExprValue *pointee = const_ptr_pointee(ira->codegen, &ptr->value); - if (!pointee) return ira->codegen->invalid_instruction; if (pointee->special != ConstValSpecialRuntime) { IrInstruction *result = ir_create_const(&ira->new_irb, source_instruction->scope, source_instruction->source_node, child_type); @@ -13656,7 +13655,6 @@ static TypeTableEntry *ir_analyze_dereference(IrAnalyze *ira, IrInstructionUnOp return ira->codegen->builtin_types.entry_invalid; ConstExprValue *pointee = const_ptr_pointee(ira->codegen, comptime_value); - if (!pointee) return ira->codegen->builtin_types.entry_invalid; if (pointee->type == child_type) { ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base); copy_const_val(out_val, pointee, value->value.data.x_ptr.mut == ConstPtrMutComptimeConst); @@ -14060,7 +14058,6 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc ptr_type = ptr_type->data.pointer.child_type; if (orig_array_ptr_val->special != ConstValSpecialRuntime) { orig_array_ptr_val = const_ptr_pointee(ira->codegen, orig_array_ptr_val); - if (!orig_array_ptr_val) return ira->codegen->builtin_types.entry_invalid; } } if (array_type->data.array.len == 0) { @@ -14102,7 +14099,6 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc if (!ptr_val) return ira->codegen->builtin_types.entry_invalid; ConstExprValue *args_val = const_ptr_pointee(ira->codegen, ptr_val); - if (!args_val) return ira->codegen->builtin_types.entry_invalid; size_t start = args_val->data.x_arg_tuple.start_index; size_t end = args_val->data.x_arg_tuple.end_index; uint64_t elem_index_val; @@ -14384,7 +14380,6 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_ if (ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) { ConstExprValue *struct_val = const_ptr_pointee(ira->codegen, ptr_val); - if (!struct_val) return ira->codegen->invalid_instruction; if (type_is_invalid(struct_val->type)) return ira->codegen->invalid_instruction; ConstExprValue *field_val = &struct_val->data.x_struct.fields[field->src_index]; @@ -14427,7 +14422,6 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_ if (ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) { ConstExprValue *union_val = const_ptr_pointee(ira->codegen, ptr_val); - if (!union_val) return ira->codegen->invalid_instruction; if (type_is_invalid(union_val->type)) return ira->codegen->invalid_instruction; @@ -14624,7 +14618,6 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru assert(container_ptr->value.type->id == TypeTableEntryIdPointer); ConstExprValue *child_val = const_ptr_pointee(ira->codegen, container_ptr_val); - if (!child_val) return ira->codegen->builtin_types.entry_invalid; if (buf_eql_str(field_name, "len")) { ConstExprValue *len_val = create_const_vals(1); @@ -14649,7 +14642,6 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru assert(container_ptr->value.type->id == TypeTableEntryIdPointer); ConstExprValue *child_val = const_ptr_pointee(ira->codegen, container_ptr_val); - if (!child_val) return ira->codegen->builtin_types.entry_invalid; TypeTableEntry *child_type = child_val->data.x_type; if (type_is_invalid(child_type)) { @@ -14918,7 +14910,6 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru return ira->codegen->builtin_types.entry_invalid; ConstExprValue *namespace_val = const_ptr_pointee(ira->codegen, container_ptr_val); - if (!namespace_val) return ira->codegen->builtin_types.entry_invalid; assert(namespace_val->special == ConstValSpecialStatic); ImportTableEntry *namespace_import = namespace_val->data.x_import; @@ -14995,7 +14986,6 @@ static TypeTableEntry *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstru if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar) { if (instr_is_comptime(casted_value)) { ConstExprValue *dest_val = const_ptr_pointee(ira->codegen, &ptr->value); - if (!dest_val) return ira->codegen->builtin_types.entry_invalid; if (dest_val->special != ConstValSpecialRuntime) { *dest_val = casted_value->value; if (!ira->new_irb.current_basic_block->must_be_comptime_source_instr) { @@ -15007,7 +14997,6 @@ static TypeTableEntry *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstru ir_add_error(ira, &store_ptr_instruction->base, buf_sprintf("cannot store runtime value in compile time variable")); ConstExprValue *dest_val = const_ptr_pointee(ira->codegen, &ptr->value); - if (!dest_val) return ira->codegen->builtin_types.entry_invalid; dest_val->type = ira->codegen->builtin_types.entry_invalid; return ira->codegen->builtin_types.entry_invalid; @@ -15861,7 +15850,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira, ConstExprValue *pointee_val = nullptr; if (instr_is_comptime(target_value_ptr)) { pointee_val = const_ptr_pointee(ira->codegen, &target_value_ptr->value); - if (pointee_val && pointee_val->special == ConstValSpecialRuntime) + if (pointee_val->special == ConstValSpecialRuntime) pointee_val = nullptr; } if ((err = ensure_complete_type(ira->codegen, target_type))) @@ -15992,7 +15981,6 @@ static TypeTableEntry *ir_analyze_instruction_switch_var(IrAnalyze *ira, IrInstr return ira->codegen->builtin_types.entry_invalid; ConstExprValue *pointee_val = const_ptr_pointee(ira->codegen, target_val_ptr); - if (!pointee_val) return ira->codegen->builtin_types.entry_invalid; ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); out_val->data.x_ptr.special = ConstPtrSpecialRef; out_val->data.x_ptr.mut = target_val_ptr->data.x_ptr.mut; @@ -18744,14 +18732,11 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio TypeTableEntry *child_array_type = array_type->data.pointer.child_type; assert(child_array_type->id == TypeTableEntryIdArray); parent_ptr = const_ptr_pointee(ira->codegen, &ptr_ptr->value); - if (!parent_ptr) return ira->codegen->builtin_types.entry_invalid; array_val = const_ptr_pointee(ira->codegen, parent_ptr); - if (!array_val) return ira->codegen->builtin_types.entry_invalid; rel_end = child_array_type->data.array.len; abs_offset = 0; } else { array_val = const_ptr_pointee(ira->codegen, &ptr_ptr->value); - if (!array_val) return ira->codegen->builtin_types.entry_invalid; rel_end = array_type->data.array.len; parent_ptr = nullptr; abs_offset = 0; @@ -18759,7 +18744,6 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio } else if (array_type->id == TypeTableEntryIdPointer) { assert(array_type->data.pointer.ptr_len == PtrLenUnknown); parent_ptr = const_ptr_pointee(ira->codegen, &ptr_ptr->value); - if (!parent_ptr) return ira->codegen->builtin_types.entry_invalid; if (parent_ptr->special == ConstValSpecialUndef) { array_val = nullptr; abs_offset = 0; @@ -18791,7 +18775,6 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio } } else if (is_slice(array_type)) { ConstExprValue *slice_ptr = const_ptr_pointee(ira->codegen, &ptr_ptr->value); - if (!slice_ptr) return ira->codegen->builtin_types.entry_invalid; parent_ptr = &slice_ptr->data.x_struct.fields[slice_ptr_index]; ConstExprValue *len_val = &slice_ptr->data.x_struct.fields[slice_len_index]; @@ -19192,7 +19175,6 @@ static TypeTableEntry *ir_analyze_instruction_overflow_op(IrAnalyze *ira, IrInst BigInt *op1_bigint = &casted_op1->value.data.x_bigint; BigInt *op2_bigint = &casted_op2->value.data.x_bigint; ConstExprValue *pointee_val = const_ptr_pointee(ira->codegen, &casted_result_ptr->value); - if (!pointee_val) return ira->codegen->builtin_types.entry_invalid; BigInt *dest_bigint = &pointee_val->data.x_bigint; switch (instruction->op) { case IrOverflowOpAdd: @@ -19293,7 +19275,6 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira, if (!ptr_val) return ira->codegen->builtin_types.entry_invalid; ConstExprValue *err_union_val = const_ptr_pointee(ira->codegen, ptr_val); - if (!err_union_val) return ira->codegen->builtin_types.entry_invalid; if (err_union_val->special != ConstValSpecialRuntime) { ErrorTableEntry *err = err_union_val->data.x_err_union.err; assert(err); @@ -19342,7 +19323,6 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira, if (!ptr_val) return ira->codegen->builtin_types.entry_invalid; ConstExprValue *err_union_val = const_ptr_pointee(ira->codegen, ptr_val); - if (!err_union_val) return ira->codegen->builtin_types.entry_invalid; if (err_union_val->special != ConstValSpecialRuntime) { ErrorTableEntry *err = err_union_val->data.x_err_union.err; if (err != nullptr) { -- cgit v1.2.3 From 68e2794e1543f91ab8f984127018820897cc0521 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 26 Aug 2018 13:13:26 -0400 Subject: ir: const_ptr_pointee asserts that its return value is non-null --- src/ir.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 5bf39ee691..ae69f9c817 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -155,18 +155,22 @@ static TypeTableEntry *adjust_slice_align(CodeGen *g, TypeTableEntry *slice_type ConstExprValue *const_ptr_pointee(CodeGen *g, ConstExprValue *const_val) { assert(get_codegen_ptr_type(const_val->type) != nullptr); assert(const_val->special == ConstValSpecialStatic); + ConstExprValue *result; switch (const_val->data.x_ptr.special) { case ConstPtrSpecialInvalid: zig_unreachable(); case ConstPtrSpecialRef: - return const_val->data.x_ptr.data.ref.pointee; + result = const_val->data.x_ptr.data.ref.pointee; + break; case ConstPtrSpecialBaseArray: expand_undef_array(g, const_val->data.x_ptr.data.base_array.array_val); - return &const_val->data.x_ptr.data.base_array.array_val->data.x_array.s_none.elements[ + result = &const_val->data.x_ptr.data.base_array.array_val->data.x_array.s_none.elements[ const_val->data.x_ptr.data.base_array.elem_index]; + break; case ConstPtrSpecialBaseStruct: - return &const_val->data.x_ptr.data.base_struct.struct_val->data.x_struct.fields[ + result = &const_val->data.x_ptr.data.base_struct.struct_val->data.x_struct.fields[ const_val->data.x_ptr.data.base_struct.field_index]; + break; case ConstPtrSpecialHardCodedAddr: zig_unreachable(); case ConstPtrSpecialDiscard: @@ -174,7 +178,8 @@ ConstExprValue *const_ptr_pointee(CodeGen *g, ConstExprValue *const_val) { case ConstPtrSpecialFunction: zig_unreachable(); } - zig_unreachable(); + assert(result != nullptr); + return result; } static bool ir_should_inline(IrExecutable *exec, Scope *scope) { -- cgit v1.2.3 From 009e90f446ec7a81d602906fda9b17a6af1859f5 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 27 Aug 2018 17:11:43 -0400 Subject: fix @typeInfo unable to distinguish compile error vs no-payload closes #1421 closes #1426 --- src/ir.cpp | 133 +++++++++++++++++++++++------------------------- test/compile_errors.zig | 17 +++++++ 2 files changed, 82 insertions(+), 68 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index ae69f9c817..710456179c 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -14444,8 +14444,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_ ConstExprValue *payload_val = union_val->data.x_union.payload; TypeTableEntry *field_type = field->type_entry; - if (field_type->id == TypeTableEntryIdVoid) - { + if (field_type->id == TypeTableEntryIdVoid) { assert(payload_val == nullptr); payload_val = create_const_vals(1); payload_val->special = ConstValSpecialStatic; @@ -16797,12 +16796,11 @@ static TypeTableEntry *ir_type_info_get_type(IrAnalyze *ira, const char *type_na return var->value->data.x_type; } -static bool ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, ScopeDecls *decls_scope) -{ +static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, ScopeDecls *decls_scope) { Error err; TypeTableEntry *type_info_definition_type = ir_type_info_get_type(ira, "Definition", nullptr); if ((err = ensure_complete_type(ira->codegen, type_info_definition_type))) - return false; + return err; ensure_field_index(type_info_definition_type, "name", 0); ensure_field_index(type_info_definition_type, "is_pub", 1); @@ -16810,38 +16808,33 @@ static bool ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Scop TypeTableEntry *type_info_definition_data_type = ir_type_info_get_type(ira, "Data", type_info_definition_type); if ((err = ensure_complete_type(ira->codegen, type_info_definition_data_type))) - return false; + return err; TypeTableEntry *type_info_fn_def_type = ir_type_info_get_type(ira, "FnDef", type_info_definition_data_type); if ((err = ensure_complete_type(ira->codegen, type_info_fn_def_type))) - return false; + return err; TypeTableEntry *type_info_fn_def_inline_type = ir_type_info_get_type(ira, "Inline", type_info_fn_def_type); if ((err = ensure_complete_type(ira->codegen, type_info_fn_def_inline_type))) - return false; + return err; // Loop through our definitions once to figure out how many definitions we will generate info for. auto decl_it = decls_scope->decl_table.entry_iterator(); decltype(decls_scope->decl_table)::Entry *curr_entry = nullptr; int definition_count = 0; - while ((curr_entry = decl_it.next()) != nullptr) - { + while ((curr_entry = decl_it.next()) != nullptr) { // If the definition is unresolved, force it to be resolved again. - if (curr_entry->value->resolution == TldResolutionUnresolved) - { + if (curr_entry->value->resolution == TldResolutionUnresolved) { resolve_top_level_decl(ira->codegen, curr_entry->value, false, curr_entry->value->source_node); - if (curr_entry->value->resolution != TldResolutionOk) - { - return false; + if (curr_entry->value->resolution != TldResolutionOk) { + return ErrorSemanticAnalyzeFail; } } // Skip comptime blocks and test functions. - if (curr_entry->value->id != TldIdCompTime) - { - if (curr_entry->value->id == TldIdFn) - { + if (curr_entry->value->id != TldIdCompTime) { + if (curr_entry->value->id == TldIdFn) { FnTableEntry *fn_entry = ((TldFn *)curr_entry->value)->fn_entry; if (fn_entry->is_test) continue; @@ -16863,13 +16856,11 @@ static bool ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Scop decl_it = decls_scope->decl_table.entry_iterator(); curr_entry = nullptr; int definition_index = 0; - while ((curr_entry = decl_it.next()) != nullptr) - { + while ((curr_entry = decl_it.next()) != nullptr) { // Skip comptime blocks and test functions. - if (curr_entry->value->id == TldIdCompTime) + if (curr_entry->value->id == TldIdCompTime) { continue; - else if (curr_entry->value->id == TldIdFn) - { + } else if (curr_entry->value->id == TldIdFn) { FnTableEntry *fn_entry = ((TldFn *)curr_entry->value)->fn_entry; if (fn_entry->is_test) continue; @@ -16892,13 +16883,12 @@ static bool ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Scop inner_fields[2].data.x_union.parent.data.p_struct.struct_val = definition_val; inner_fields[2].data.x_union.parent.data.p_struct.field_index = 1; - switch (curr_entry->value->id) - { + switch (curr_entry->value->id) { case TldIdVar: { VariableTableEntry *var = ((TldVar *)curr_entry->value)->var; if ((err = ensure_complete_type(ira->codegen, var->value->type))) - return false; + return ErrorSemanticAnalyzeFail; if (var->value->type->id == TypeTableEntryIdMetaType) { @@ -17029,7 +17019,7 @@ static bool ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Scop { TypeTableEntry *type_entry = ((TldContainer *)curr_entry->value)->type_entry; if ((err = ensure_complete_type(ira->codegen, type_entry))) - return false; + return ErrorSemanticAnalyzeFail; // This is a type. bigint_init_unsigned(&inner_fields[2].data.x_union.tag, 0); @@ -17051,7 +17041,7 @@ static bool ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Scop } assert(definition_index == definition_count); - return true; + return ErrorNone; } static ConstExprValue *create_ptr_like_type_info(IrAnalyze *ira, TypeTableEntry *ptr_type_entry) { @@ -17109,30 +17099,31 @@ static ConstExprValue *create_ptr_like_type_info(IrAnalyze *ira, TypeTableEntry return result; }; -static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *type_entry) { - Error err; - assert(type_entry != nullptr); - assert(!type_is_invalid(type_entry)); +static void make_enum_field_val(IrAnalyze *ira, ConstExprValue *enum_field_val, TypeEnumField *enum_field, + TypeTableEntry *type_info_enum_field_type) +{ + enum_field_val->special = ConstValSpecialStatic; + enum_field_val->type = type_info_enum_field_type; - if ((err = ensure_complete_type(ira->codegen, type_entry))) - return nullptr; + ConstExprValue *inner_fields = create_const_vals(2); + inner_fields[1].special = ConstValSpecialStatic; + inner_fields[1].type = ira->codegen->builtin_types.entry_usize; - const auto make_enum_field_val = [ira](ConstExprValue *enum_field_val, TypeEnumField *enum_field, - TypeTableEntry *type_info_enum_field_type) { - enum_field_val->special = ConstValSpecialStatic; - enum_field_val->type = type_info_enum_field_type; + ConstExprValue *name = create_const_str_lit(ira->codegen, enum_field->name); + init_const_slice(ira->codegen, &inner_fields[0], name, 0, buf_len(enum_field->name), true); - ConstExprValue *inner_fields = create_const_vals(2); - inner_fields[1].special = ConstValSpecialStatic; - inner_fields[1].type = ira->codegen->builtin_types.entry_usize; + bigint_init_bigint(&inner_fields[1].data.x_bigint, &enum_field->value); - ConstExprValue *name = create_const_str_lit(ira->codegen, enum_field->name); - init_const_slice(ira->codegen, &inner_fields[0], name, 0, buf_len(enum_field->name), true); + enum_field_val->data.x_struct.fields = inner_fields; +} - bigint_init_bigint(&inner_fields[1].data.x_bigint, &enum_field->value); +static Error ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *type_entry, ConstExprValue **out) { + Error err; + assert(type_entry != nullptr); + assert(!type_is_invalid(type_entry)); - enum_field_val->data.x_struct.fields = inner_fields; - }; + if ((err = ensure_complete_type(ira->codegen, type_entry))) + return err; if (type_entry == ira->codegen->builtin_types.entry_global_error_set) { zig_panic("TODO implement @typeInfo for global error set"); @@ -17155,13 +17146,16 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t case TypeTableEntryIdBlock: case TypeTableEntryIdArgTuple: case TypeTableEntryIdOpaque: - return nullptr; + *out = nullptr; + return ErrorNone; default: { // Lookup an available value in our cache. auto entry = ira->codegen->type_info_cache.maybe_get(type_entry); - if (entry != nullptr) - return entry->value; + if (entry != nullptr) { + *out = entry->value; + return ErrorNone; + } // Fallthrough if we don't find one. } @@ -17312,15 +17306,15 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t { TypeEnumField *enum_field = &type_entry->data.enumeration.fields[enum_field_index]; ConstExprValue *enum_field_val = &enum_field_array->data.x_array.s_none.elements[enum_field_index]; - make_enum_field_val(enum_field_val, enum_field, type_info_enum_field_type); + make_enum_field_val(ira, enum_field_val, enum_field, type_info_enum_field_type); enum_field_val->data.x_struct.parent.id = ConstParentIdArray; enum_field_val->data.x_struct.parent.data.p_array.array_val = enum_field_array; enum_field_val->data.x_struct.parent.data.p_array.elem_index = enum_field_index; } // defs: []TypeInfo.Definition ensure_field_index(result->type, "defs", 3); - if (!ir_make_type_info_defs(ira, &fields[3], type_entry->data.enumeration.decls_scope)) - return nullptr; + if ((err = ir_make_type_info_defs(ira, &fields[3], type_entry->data.enumeration.decls_scope))) + return err; break; } @@ -17346,8 +17340,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t error_array->data.x_array.s_none.elements = create_const_vals(error_count); init_const_slice(ira->codegen, &fields[0], error_array, 0, error_count, false); - for (uint32_t error_index = 0; error_index < error_count; error_index++) - { + for (uint32_t error_index = 0; error_index < error_count; error_index++) { ErrorTableEntry *error = type_entry->data.error_set.errors[error_index]; ConstExprValue *error_val = &error_array->data.x_array.s_none.elements[error_index]; @@ -17425,9 +17418,9 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t tag_type->type = ira->codegen->builtin_types.entry_type; tag_type->data.x_type = type_entry->data.unionation.tag_type; fields[1].data.x_optional = tag_type; - } - else + } else { fields[1].data.x_optional = nullptr; + } // fields: []TypeInfo.UnionField ensure_field_index(result->type, "fields", 2); @@ -17460,7 +17453,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t inner_fields[1].data.x_optional = nullptr; } else { inner_fields[1].data.x_optional = create_const_vals(1); - make_enum_field_val(inner_fields[1].data.x_optional, union_field->enum_field, type_info_enum_field_type); + make_enum_field_val(ira, inner_fields[1].data.x_optional, union_field->enum_field, type_info_enum_field_type); } inner_fields[2].special = ConstValSpecialStatic; @@ -17477,8 +17470,8 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t } // defs: []TypeInfo.Definition ensure_field_index(result->type, "defs", 3); - if (!ir_make_type_info_defs(ira, &fields[3], type_entry->data.unionation.decls_scope)) - return nullptr; + if ((err = ir_make_type_info_defs(ira, &fields[3], type_entry->data.unionation.decls_scope))) + return err; break; } @@ -17551,8 +17544,8 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t } // defs: []TypeInfo.Definition ensure_field_index(result->type, "defs", 2); - if (!ir_make_type_info_defs(ira, &fields[2], type_entry->data.structure.decls_scope)) - return nullptr; + if ((err = ir_make_type_info_defs(ira, &fields[2], type_entry->data.structure.decls_scope))) + return err; break; } @@ -17665,7 +17658,8 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t { TypeTableEntry *fn_type = type_entry->data.bound_fn.fn_type; assert(fn_type->id == TypeTableEntryIdFn); - result = ir_make_type_info_value(ira, fn_type); + if ((err = ir_make_type_info_value(ira, fn_type, &result))) + return err; break; } @@ -17673,12 +17667,14 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t assert(result != nullptr); ira->codegen->type_info_cache.put(type_entry, result); - return result; + *out = result; + return ErrorNone; } static TypeTableEntry *ir_analyze_instruction_type_info(IrAnalyze *ira, IrInstructionTypeInfo *instruction) { + Error err; IrInstruction *type_value = instruction->type_value->other; TypeTableEntry *type_entry = ir_resolve_type(ira, type_value); if (type_is_invalid(type_entry)) @@ -17686,15 +17682,16 @@ static TypeTableEntry *ir_analyze_instruction_type_info(IrAnalyze *ira, TypeTableEntry *result_type = ir_type_info_get_type(ira, nullptr, nullptr); + ConstExprValue *payload; + if ((err = ir_make_type_info_value(ira, type_entry, &payload))) + return ira->codegen->builtin_types.entry_invalid; + ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); out_val->type = result_type; bigint_init_unsigned(&out_val->data.x_union.tag, type_id_index(type_entry)); - - ConstExprValue *payload = ir_make_type_info_value(ira, type_entry); out_val->data.x_union.payload = payload; - if (payload != nullptr) - { + if (payload != nullptr) { assert(payload->type->id == TypeTableEntryIdStruct); payload->data.x_struct.parent.id = ConstParentIdUnion; payload->data.x_struct.parent.data.p_union.union_val = out_val; diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 56b2c51d74..d0795c4550 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1,6 +1,23 @@ const tests = @import("tests.zig"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.add( + "@typeInfo causing depend on itself compile error", + \\const start = struct { + \\ fn crash() bug() { + \\ return bug; + \\ } + \\}; + \\fn bug() void { + \\ _ = @typeInfo(start).Struct; + \\} + \\export fn entry() void { + \\ var boom = start.crash(); + \\} + , + ".tmp_source.zig:2:5: error: 'crash' depends on itself", + ); + cases.add( "@handle() called outside of function definition", \\var handle_undef: promise = undefined; -- cgit v1.2.3 From e2a9f2ef988e6ff4ec9f943ead9285c67c56ffd7 Mon Sep 17 00:00:00 2001 From: raulgrell Date: Mon, 27 Aug 2018 16:37:37 +0100 Subject: Allow implicit cast from *T and [*]T to ?*c_void --- src/ir.cpp | 20 ++++++++++++++++---- test/cases/cast.zig | 24 ++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 4 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 710456179c..b4af7f42e2 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -60,7 +60,7 @@ enum ConstCastResultId { ConstCastResultIdType, ConstCastResultIdUnresolvedInferredErrSet, ConstCastResultIdAsyncAllocatorType, - ConstCastResultIdNullWrapPtr, + ConstCastResultIdNullWrapPtr }; struct ConstCastOnly; @@ -8471,9 +8471,9 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry if (wanted_type == actual_type) return result; - // * and [*] can do a const-cast-only to ?* and ?[*], respectively - // but not if there is a mutable parent pointer - // and not if the pointer is zero bits + // *T and [*]T may const-cast-only to ?*U and ?[*]U, respectively + // but not if we want a mutable pointer + // and not if the actual pointer has zero bits if (!wanted_is_mutable && wanted_type->id == TypeTableEntryIdOptional && wanted_type->data.maybe.child_type->id == TypeTableEntryIdPointer && actual_type->id == TypeTableEntryIdPointer && type_has_bits(actual_type)) @@ -8488,6 +8488,18 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry return result; } + // *T and [*]T can always cast to ?*c_void + if (wanted_type->id == TypeTableEntryIdPointer && + wanted_type->data.pointer.ptr_len == PtrLenSingle && + wanted_type->data.pointer.child_type == g->builtin_types.entry_c_void && + actual_type->id == TypeTableEntryIdPointer && + (!actual_type->data.pointer.is_const || wanted_type->data.pointer.is_const) && + (!actual_type->data.pointer.is_volatile || wanted_type->data.pointer.is_volatile)) + { + assert(actual_type->data.pointer.alignment >= wanted_type->data.pointer.alignment); + return result; + } + // pointer const if (wanted_type->id == TypeTableEntryIdPointer && actual_type->id == TypeTableEntryIdPointer) { ConstCastOnly child = types_match_const_cast_only(ira, wanted_type->data.pointer.child_type, diff --git a/test/cases/cast.zig b/test/cases/cast.zig index df37bd1dd9..dde714b2be 100644 --- a/test/cases/cast.zig +++ b/test/cases/cast.zig @@ -495,4 +495,28 @@ test "implicit cast from *[N]T to ?[*]T" { x.?[0] = 8; y[3] = 6; assert(std.mem.eql(u16, x.?[0..4], y[0..4])); +} + +test "implicit cast from *T to ?*c_void" { + var a: u8 = 1; + incrementVoidPtrValue(&a); + std.debug.assert(a == 2); +} + +fn incrementVoidPtrValue(value: ?*c_void) void { + @ptrCast(*u8, value.?).* += 1; +} + +test "implicit cast from [*]T to ?*c_void" { + var a = []u8{3, 2, 1}; + incrementVoidPtrArray(a[0..].ptr, 3); + std.debug.assert(std.mem.eql(u8, a, []u8{4, 3, 2})); +} + +fn incrementVoidPtrArray(array: ?*c_void, len: usize) void { + var n: usize = 0; + while(n < len) : (n += 1) { + std.debug.warn("{}", n); + @ptrCast([*]u8, array.?)[n] += 1; + } } \ No newline at end of file -- cgit v1.2.3 From 45d9d9f953df2167b35878ea02551d9c86ad8a0f Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 27 Aug 2018 18:31:28 -0400 Subject: minor fixups --- src/ir.cpp | 2 +- test/cases/cast.zig | 31 +++++++++++++++---------------- 2 files changed, 16 insertions(+), 17 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index b4af7f42e2..3117410cd2 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -8488,7 +8488,7 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry return result; } - // *T and [*]T can always cast to ?*c_void + // *T and [*]T can always cast to *c_void if (wanted_type->id == TypeTableEntryIdPointer && wanted_type->data.pointer.ptr_len == PtrLenSingle && wanted_type->data.pointer.child_type == g->builtin_types.entry_c_void && diff --git a/test/cases/cast.zig b/test/cases/cast.zig index dde714b2be..cc5e4b4394 100644 --- a/test/cases/cast.zig +++ b/test/cases/cast.zig @@ -487,20 +487,20 @@ fn MakeType(comptime T: type) type { } test "implicit cast from *[N]T to ?[*]T" { - var x: ?[*]u16 = null; - var y: [4]u16 = [4]u16 {0, 1, 2, 3}; + var x: ?[*]u16 = null; + var y: [4]u16 = [4]u16{ 0, 1, 2, 3 }; - x = &y; - assert(std.mem.eql(u16, x.?[0..4], y[0..4])); - x.?[0] = 8; - y[3] = 6; - assert(std.mem.eql(u16, x.?[0..4], y[0..4])); + x = &y; + assert(std.mem.eql(u16, x.?[0..4], y[0..4])); + x.?[0] = 8; + y[3] = 6; + assert(std.mem.eql(u16, x.?[0..4], y[0..4])); } test "implicit cast from *T to ?*c_void" { - var a: u8 = 1; - incrementVoidPtrValue(&a); - std.debug.assert(a == 2); + var a: u8 = 1; + incrementVoidPtrValue(&a); + std.debug.assert(a == 2); } fn incrementVoidPtrValue(value: ?*c_void) void { @@ -508,15 +508,14 @@ fn incrementVoidPtrValue(value: ?*c_void) void { } test "implicit cast from [*]T to ?*c_void" { - var a = []u8{3, 2, 1}; - incrementVoidPtrArray(a[0..].ptr, 3); - std.debug.assert(std.mem.eql(u8, a, []u8{4, 3, 2})); + var a = []u8{ 3, 2, 1 }; + incrementVoidPtrArray(a[0..].ptr, 3); + assert(std.mem.eql(u8, a, []u8{ 4, 3, 2 })); } fn incrementVoidPtrArray(array: ?*c_void, len: usize) void { var n: usize = 0; - while(n < len) : (n += 1) { - std.debug.warn("{}", n); + while (n < len) : (n += 1) { @ptrCast([*]u8, array.?)[n] += 1; } -} \ No newline at end of file +} -- cgit v1.2.3 From 09cc1dc66067f378a1508e34c0714b659b445724 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 28 Aug 2018 15:24:28 -0400 Subject: fix crash when var in inline loop has different types closes #917 closes #845 closes #741 closes #740 --- src/all_types.hpp | 5 +++++ src/ir.cpp | 64 +++++++++++++++++++++++++++++++---------------------- test/cases/eval.zig | 13 +++++++++++ test/cases/for.zig | 6 ++--- 4 files changed, 58 insertions(+), 30 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index a8dd9dde83..6f0dd9baac 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1807,6 +1807,11 @@ struct VariableTableEntry { VarLinkage linkage; IrInstruction *decl_instruction; uint32_t align_bytes; + + // In an inline loop, multiple variables may be created, + // In this case, a reference to a variable should follow + // this pointer to the redefined variable. + VariableTableEntry *next_var; }; struct ErrorTableEntry { diff --git a/src/ir.cpp b/src/ir.cpp index 3117410cd2..4e64b3e002 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -3280,7 +3280,8 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, } static VariableTableEntry *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_scope, - Buf *name, bool src_is_const, bool gen_is_const, bool is_shadowable, IrInstruction *is_comptime) + Buf *name, bool src_is_const, bool gen_is_const, bool is_shadowable, IrInstruction *is_comptime, + bool skip_name_check) { VariableTableEntry *variable_entry = allocate(1); variable_entry->parent_scope = parent_scope; @@ -3293,29 +3294,30 @@ static VariableTableEntry *create_local_var(CodeGen *codegen, AstNode *node, Sco if (name) { buf_init_from_buf(&variable_entry->name, name); - VariableTableEntry *existing_var = find_variable(codegen, parent_scope, name); - if (existing_var && !existing_var->shadowable) { - ErrorMsg *msg = add_node_error(codegen, node, - buf_sprintf("redeclaration of variable '%s'", buf_ptr(name))); - add_error_note(codegen, msg, existing_var->decl_node, buf_sprintf("previous declaration is here")); - variable_entry->value->type = codegen->builtin_types.entry_invalid; - } else { - TypeTableEntry *type = get_primitive_type(codegen, name); - if (type != nullptr) { - add_node_error(codegen, node, - buf_sprintf("variable shadows type '%s'", buf_ptr(&type->name))); + if (!skip_name_check) { + VariableTableEntry *existing_var = find_variable(codegen, parent_scope, name); + if (existing_var && !existing_var->shadowable) { + ErrorMsg *msg = add_node_error(codegen, node, + buf_sprintf("redeclaration of variable '%s'", buf_ptr(name))); + add_error_note(codegen, msg, existing_var->decl_node, buf_sprintf("previous declaration is here")); variable_entry->value->type = codegen->builtin_types.entry_invalid; } else { - Tld *tld = find_decl(codegen, parent_scope, name); - if (tld != nullptr) { - ErrorMsg *msg = add_node_error(codegen, node, - buf_sprintf("redefinition of '%s'", buf_ptr(name))); - add_error_note(codegen, msg, tld->source_node, buf_sprintf("previous definition is here")); + TypeTableEntry *type = get_primitive_type(codegen, name); + if (type != nullptr) { + add_node_error(codegen, node, + buf_sprintf("variable shadows type '%s'", buf_ptr(&type->name))); variable_entry->value->type = codegen->builtin_types.entry_invalid; + } else { + Tld *tld = find_decl(codegen, parent_scope, name); + if (tld != nullptr) { + ErrorMsg *msg = add_node_error(codegen, node, + buf_sprintf("redefinition of '%s'", buf_ptr(name))); + add_error_note(codegen, msg, tld->source_node, buf_sprintf("previous definition is here")); + variable_entry->value->type = codegen->builtin_types.entry_invalid; + } } } } - } else { assert(is_shadowable); // TODO make this name not actually be in scope. user should be able to make a variable called "_anon" @@ -3338,14 +3340,9 @@ static VariableTableEntry *ir_create_var(IrBuilder *irb, AstNode *node, Scope *s bool src_is_const, bool gen_is_const, bool is_shadowable, IrInstruction *is_comptime) { bool is_underscored = name ? buf_eql_str(name, "_") : false; - VariableTableEntry *var = create_local_var( irb->codegen - , node - , scope - , (is_underscored ? nullptr : name) - , src_is_const - , gen_is_const - , (is_underscored ? true : is_shadowable) - , is_comptime ); + VariableTableEntry *var = create_local_var(irb->codegen, node, scope, + (is_underscored ? nullptr : name), src_is_const, gen_is_const, + (is_underscored ? true : is_shadowable), is_comptime, false); if (is_comptime != nullptr || gen_is_const) { var->mem_slot_index = exec_next_mem_slot(irb->exec); var->owner_exec = irb->exec; @@ -12495,6 +12492,17 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc } } + if (var->value->type != nullptr && var->value->type != result_type && !is_comptime_var) { + // This is at least the second time we've seen this variable declaration during analysis. + // This means that this is actually a different variable due to, e.g. an inline while loop. + // We make a new variable so that it can hold a different type, and so the debug info can + // be distinct. + VariableTableEntry *new_var = create_local_var(ira->codegen, var->decl_node, var->child_scope, + &var->name, var->src_is_const, var->gen_is_const, var->shadowable, var->is_comptime, true); + var->next_var = new_var; + var = new_var; + } + var->value->type = result_type; assert(var->value->type); @@ -12977,6 +12985,10 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, VariableTableEntry *var) { Error err; + while (var->next_var != nullptr) { + var = var->next_var; + } + if (var->mem_slot_index != SIZE_MAX && var->owner_exec->analysis == nullptr) { assert(ira->codegen->errors.length != 0); return ira->codegen->invalid_instruction; diff --git a/test/cases/eval.zig b/test/cases/eval.zig index 9da475994d..96b9e14cf5 100644 --- a/test/cases/eval.zig +++ b/test/cases/eval.zig @@ -652,3 +652,16 @@ fn loopNTimes(comptime n: usize) void { comptime var i = 0; inline while (i < n) : (i += 1) {} } + +test "variable inside inline loop that has different types on different iterations" { + testVarInsideInlineLoop(true, u32(42)); +} + +fn testVarInsideInlineLoop(args: ...) void { + comptime var i = 0; + inline while (i < args.len) : (i += 1) { + const x = args[i]; + if (i == 0) assert(x); + if (i == 1) assert(x == 42); + } +} diff --git a/test/cases/for.zig b/test/cases/for.zig index 59d90c1b85..f943515cc1 100644 --- a/test/cases/for.zig +++ b/test/cases/for.zig @@ -71,8 +71,7 @@ fn testBreakOuter() void { var array = "aoeu"; var count: usize = 0; outer: for (array) |_| { - // TODO shouldn't get error for redeclaring "_" - for (array) |_2| { + for (array) |_| { count += 1; break :outer; } @@ -89,8 +88,7 @@ fn testContinueOuter() void { var array = "aoeu"; var counter: usize = 0; outer: for (array) |_| { - // TODO shouldn't get error for redeclaring "_" - for (array) |_2| { + for (array) |_| { counter += 1; continue :outer; } -- cgit v1.2.3 From 95636c7e5ff6ad0eeb768a2a0a1d7533b5872e20 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 3 Sep 2018 00:04:12 -0400 Subject: ability to @ptrCast to *void fixes #960 --- src/codegen.cpp | 3 +++ src/ir.cpp | 10 ++++++++-- test/cases/cast.zig | 6 ++++++ 3 files changed, 17 insertions(+), 2 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index 388a1a371f..298e89579f 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2655,6 +2655,9 @@ static LLVMValueRef ir_render_ptr_cast(CodeGen *g, IrExecutable *executable, IrInstructionPtrCast *instruction) { TypeTableEntry *wanted_type = instruction->base.value.type; + if (!type_has_bits(wanted_type)) { + return nullptr; + } LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr); return LLVMBuildBitCast(g->builder, ptr, wanted_type->type_ref, ""); } diff --git a/src/ir.cpp b/src/ir.cpp index 4e64b3e002..2c3fadfc2d 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -19757,6 +19757,8 @@ static IrInstruction *ir_align_cast(IrAnalyze *ira, IrInstruction *target, uint3 } static TypeTableEntry *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstructionPtrCast *instruction) { + Error err; + IrInstruction *dest_type_value = instruction->dest_type->other; TypeTableEntry *dest_type = ir_resolve_type(ira, dest_type_value); if (type_is_invalid(dest_type)) @@ -19810,9 +19812,13 @@ static TypeTableEntry *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstruc instruction->base.source_node, nullptr, ptr); casted_ptr->value.type = dest_type; - // keep the bigger alignment, it can only help + // Keep the bigger alignment, it can only help- + // unless the target is zero bits. + if ((err = type_ensure_zero_bits_known(ira->codegen, dest_type))) + return ira->codegen->builtin_types.entry_invalid; + IrInstruction *result; - if (src_align_bytes > dest_align_bytes) { + if (src_align_bytes > dest_align_bytes && type_has_bits(dest_type)) { result = ir_align_cast(ira, casted_ptr, src_align_bytes, false); if (type_is_invalid(result->value.type)) return ira->codegen->builtin_types.entry_invalid; diff --git a/test/cases/cast.zig b/test/cases/cast.zig index cc5e4b4394..2b455ccc43 100644 --- a/test/cases/cast.zig +++ b/test/cases/cast.zig @@ -519,3 +519,9 @@ fn incrementVoidPtrArray(array: ?*c_void, len: usize) void { @ptrCast([*]u8, array.?)[n] += 1; } } + +test "*usize to *void" { + var i = usize(0); + var v = @ptrCast(*void, &i); + v.* = {}; +} -- cgit v1.2.3 From 2a9329c9988430cfa11a8bb4b02da0dce8749028 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 3 Sep 2018 11:32:39 -0400 Subject: better anonymous struct naming this makes anonymous structs inherit the name of the function they are in only when they are the return expression. also document the behavior and provide examples. closes #1243 --- doc/langref.html.in | 26 ++++++++++++++++++++++++++ src/all_types.hpp | 1 + src/ir.cpp | 27 ++++++++++++++------------- 3 files changed, 41 insertions(+), 13 deletions(-) (limited to 'src/ir.cpp') diff --git a/doc/langref.html.in b/doc/langref.html.in index 31d923e84b..97263347c7 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -1918,6 +1918,32 @@ test "linked list" { assert(list2.first.?.data == 1234); } {#code_end#} + {#header_open|struct naming#} +

Since all structs are anonymous, Zig infers the type name based on a few rules.

+
    +
  • If the struct is in the initialization expression of a variable, it gets named after + that variable.
  • +
  • If the struct is in the return expression, it gets named after + the function it is returning from, with the parameter values serialized.
  • +
  • Otherwise, the struct gets a same such as (anonymous struct at file.zig:7:38).
  • +
+ {#code_begin|exe|struct_name#} +const std = @import("std"); + +pub fn main() void { + const Foo = struct {}; + std.debug.warn("variable: {}\n", @typeName(Foo)); + std.debug.warn("anonymous: {}\n", @typeName(struct {})); + std.debug.warn("function: {}\n", @typeName(List(i32))); +} + +fn List(comptime T: type) type { + return struct { + x: T, + }; +} + {#code_end#} + {#header_close#} {#see_also|comptime|@fieldParentPtr#} {#header_close#} {#header_open|enum#} diff --git a/src/all_types.hpp b/src/all_types.hpp index 6f0dd9baac..d580191afe 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -43,6 +43,7 @@ struct IrAnalyze; struct IrExecutable { ZigList basic_block_list; Buf *name; + FnTableEntry *name_fn; size_t mem_slot_count; size_t next_debug_id; size_t *backward_branch_count; diff --git a/src/ir.cpp b/src/ir.cpp index 2c3fadfc2d..5d1bbe3c08 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -3186,7 +3186,11 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, { IrInstruction *return_value; if (expr_node) { + // Temporarily set this so that if we return a type it gets the name of the function + FnTableEntry *prev_name_fn = irb->exec->name_fn; + irb->exec->name_fn = exec_fn_entry(irb->exec); return_value = ir_gen_node(irb, expr_node, scope); + irb->exec->name_fn = prev_name_fn; if (return_value == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; } else { @@ -6481,20 +6485,17 @@ static bool render_instance_name_recursive(CodeGen *codegen, Buf *name, Scope *o static Buf *get_anon_type_name(CodeGen *codegen, IrExecutable *exec, const char *kind_name, AstNode *source_node) { if (exec->name) { return exec->name; + } else if (exec->name_fn != nullptr) { + Buf *name = buf_alloc(); + buf_append_buf(name, &exec->name_fn->symbol_name); + buf_appendf(name, "("); + render_instance_name_recursive(codegen, name, &exec->name_fn->fndef_scope->base, exec->begin_scope); + buf_appendf(name, ")"); + return name; } else { - FnTableEntry *fn_entry = exec_fn_entry(exec); - if (fn_entry) { - Buf *name = buf_alloc(); - buf_append_buf(name, &fn_entry->symbol_name); - buf_appendf(name, "("); - render_instance_name_recursive(codegen, name, &fn_entry->fndef_scope->base, exec->begin_scope); - buf_appendf(name, ")"); - return name; - } else { - //Note: C-imports do not have valid location information - return buf_sprintf("(anonymous %s at %s:%" ZIG_PRI_usize ":%" ZIG_PRI_usize ")", kind_name, - (source_node->owner->path != nullptr) ? buf_ptr(source_node->owner->path) : "(null)", source_node->line + 1, source_node->column + 1); - } + //Note: C-imports do not have valid location information + return buf_sprintf("(anonymous %s at %s:%" ZIG_PRI_usize ":%" ZIG_PRI_usize ")", kind_name, + (source_node->owner->path != nullptr) ? buf_ptr(source_node->owner->path) : "(null)", source_node->line + 1, source_node->column + 1); } } -- cgit v1.2.3 From a11e73bee2266d4c568bdf9b23c891ac1365bb09 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 3 Sep 2018 12:38:24 -0400 Subject: compile error instead of segfault for unimplemented feature closes #1103 --- src/ir.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 5d1bbe3c08..98c749f623 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -6693,7 +6693,10 @@ static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNo return irb->codegen->invalid_instruction; } } else { - return_type = nullptr; + add_node_error(irb->codegen, node, + buf_sprintf("TODO implement inferred return types https://github.com/ziglang/zig/issues/447")); + return irb->codegen->invalid_instruction; + //return_type = nullptr; } IrInstruction *async_allocator_type_value = nullptr; -- cgit v1.2.3 From e82cd53df483aa08354de935879a0f9935ba4a1b Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 3 Sep 2018 21:24:20 -0400 Subject: fix incorrect value for inline loop 09cc1dc66067f378 failed to handle mem_slot_index correctly closes #1436 --- src/ir.cpp | 30 +++++++++++++++++++----------- test/cases/eval.zig | 9 +++++++++ 2 files changed, 28 insertions(+), 11 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 98c749f623..6eacb66f5c 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -17,8 +17,7 @@ #include "util.hpp" struct IrExecContext { - ConstExprValue *mem_slot_list; - size_t mem_slot_count; + ZigList mem_slot_list; }; struct IrBuilder { @@ -12496,13 +12495,20 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc } } - if (var->value->type != nullptr && var->value->type != result_type && !is_comptime_var) { + if (var->value->type != nullptr && !is_comptime_var) { // This is at least the second time we've seen this variable declaration during analysis. // This means that this is actually a different variable due to, e.g. an inline while loop. // We make a new variable so that it can hold a different type, and so the debug info can // be distinct. VariableTableEntry *new_var = create_local_var(ira->codegen, var->decl_node, var->child_scope, &var->name, var->src_is_const, var->gen_is_const, var->shadowable, var->is_comptime, true); + new_var->owner_exec = var->owner_exec; + if (var->mem_slot_index != SIZE_MAX) { + ConstExprValue *vals = create_const_vals(1); + new_var->mem_slot_index = ira->exec_context.mem_slot_list.length; + ira->exec_context.mem_slot_list.append(vals); + } + var->next_var = new_var; var = new_var; } @@ -12525,10 +12531,9 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc if (casted_init_value->value.special != ConstValSpecialRuntime) { if (var->mem_slot_index != SIZE_MAX) { - assert(var->mem_slot_index < ira->exec_context.mem_slot_count); - ConstExprValue *mem_slot = &ira->exec_context.mem_slot_list[var->mem_slot_index]; - copy_const_val(mem_slot, &casted_init_value->value, - !is_comptime_var || var->gen_is_const); + assert(var->mem_slot_index < ira->exec_context.mem_slot_list.length); + ConstExprValue *mem_slot = ira->exec_context.mem_slot_list.at(var->mem_slot_index); + copy_const_val(mem_slot, &casted_init_value->value, !is_comptime_var || var->gen_is_const); if (is_comptime_var || (var_class_requires_const && var->gen_is_const)) { ir_build_const_from(ira, &decl_var_instruction->base); @@ -13012,8 +13017,8 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, assert(var->owner_exec != nullptr); assert(var->owner_exec->analysis != nullptr); IrExecContext *exec_context = &var->owner_exec->analysis->exec_context; - assert(var->mem_slot_index < exec_context->mem_slot_count); - mem_slot = &exec_context->mem_slot_list[var->mem_slot_index]; + assert(var->mem_slot_index < exec_context->mem_slot_list.length); + mem_slot = exec_context->mem_slot_list.at(var->mem_slot_index); } } @@ -21228,8 +21233,11 @@ TypeTableEntry *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutabl ira->new_irb.codegen = codegen; ira->new_irb.exec = new_exec; - ira->exec_context.mem_slot_count = ira->old_irb.exec->mem_slot_count; - ira->exec_context.mem_slot_list = create_const_vals(ira->exec_context.mem_slot_count); + ConstExprValue *vals = create_const_vals(ira->old_irb.exec->mem_slot_count); + ira->exec_context.mem_slot_list.resize(ira->old_irb.exec->mem_slot_count); + for (size_t i = 0; i < ira->exec_context.mem_slot_list.length; i += 1) { + ira->exec_context.mem_slot_list.items[i] = &vals[i]; + } IrBasicBlock *old_entry_bb = ira->old_irb.exec->basic_block_list.at(0); IrBasicBlock *new_entry_bb = ir_get_new_bb(ira, old_entry_bb, nullptr); diff --git a/test/cases/eval.zig b/test/cases/eval.zig index 96b9e14cf5..695cd4df77 100644 --- a/test/cases/eval.zig +++ b/test/cases/eval.zig @@ -665,3 +665,12 @@ fn testVarInsideInlineLoop(args: ...) void { if (i == 1) assert(x == 42); } } + +test "inline for with same type but different values" { + var res: usize = 0; + inline for ([]type{ [2]u8, [1]u8, [2]u8 }) |T| { + var a: T = undefined; + res += a.len; + } + assert(res == 5); +} -- cgit v1.2.3 From bc88ef2dc331733e69ed895b7a815ba0a6996dc3 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 3 Sep 2018 22:47:23 -0400 Subject: compile errors for unimplemented minValue/maxValue builtins --- src/analyze.cpp | 2 -- src/ir.cpp | 8 +------- 2 files changed, 1 insertion(+), 9 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/analyze.cpp b/src/analyze.cpp index 405e010ba4..85b34cb017 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -5624,8 +5624,6 @@ void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue * if (type_entry->id == TypeTableEntryIdInt) { const_val->special = ConstValSpecialStatic; eval_min_max_value_int(g, type_entry, &const_val->data.x_bigint, is_max); - } else if (type_entry->id == TypeTableEntryIdFloat) { - zig_panic("TODO analyze_min_max_value float"); } else if (type_entry->id == TypeTableEntryIdBool) { const_val->special = ConstValSpecialStatic; const_val->data.x_bool = is_max; diff --git a/src/ir.cpp b/src/ir.cpp index 6eacb66f5c..8bf0e710b3 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -16482,12 +16482,6 @@ static TypeTableEntry *ir_analyze_min_max(IrAnalyze *ira, IrInstruction *source_ eval_min_max_value(ira->codegen, target_type, out_val, is_max); return ira->codegen->builtin_types.entry_num_lit_int; } - case TypeTableEntryIdFloat: - { - ConstExprValue *out_val = ir_build_const_from(ira, source_instruction); - eval_min_max_value(ira->codegen, target_type, out_val, is_max); - return ira->codegen->builtin_types.entry_num_lit_float; - } case TypeTableEntryIdBool: case TypeTableEntryIdVoid: { @@ -16496,7 +16490,7 @@ static TypeTableEntry *ir_analyze_min_max(IrAnalyze *ira, IrInstruction *source_ return target_type; } case TypeTableEntryIdEnum: - zig_panic("TODO min/max value for enum type"); + case TypeTableEntryIdFloat: case TypeTableEntryIdMetaType: case TypeTableEntryIdUnreachable: case TypeTableEntryIdPointer: -- cgit v1.2.3