From 1696e943acd67119104f303467c0e26eecb94544 Mon Sep 17 00:00:00 2001 From: Tadeo Kondrak Date: Tue, 28 Apr 2020 11:14:47 -0600 Subject: Implement @typeInfo for @Frame() Closes https://github.com/ziglang/zig/issues/3066 --- src/ir.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index f37f91088a..0111a33f34 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -25166,9 +25166,18 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy break; } case ZigTypeIdFnFrame: - ir_add_error(ira, source_instr, - buf_sprintf("compiler bug: TODO @typeInfo for async function frames. https://github.com/ziglang/zig/issues/3066")); - return ErrorSemanticAnalyzeFail; + { + result = ira->codegen->pass1_arena->create(); + result->special = ConstValSpecialStatic; + result->type = ir_type_info_get_type(ira, "Frame", nullptr); + ZigValue **fields = alloc_const_vals_ptrs(ira->codegen, 1); + result->data.x_struct.fields = fields; + ZigFn *fn = type_entry->data.frame.fn; + // function: var + ensure_field_index(result->type, "function", 0); + fields[0] = create_const_fn(ira->codegen, fn); + break; + } } assert(result != nullptr); -- cgit v1.2.3 From ca6db2d008cf3e0e3700e84400bd3d6e259e3c0f Mon Sep 17 00:00:00 2001 From: Tadeo Kondrak Date: Tue, 28 Apr 2020 11:16:11 -0600 Subject: Implement @Type() for EnumLiteral and FnFrame --- lib/std/builtin.zig | 8 +++++++- src/ir.cpp | 12 ++++++++++-- test/stage1/behavior/type.zig | 16 ++++++++++++++++ 3 files changed, 33 insertions(+), 3 deletions(-) (limited to 'src/ir.cpp') diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index af8033ae91..9d419f9af2 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -157,7 +157,7 @@ pub const TypeInfo = union(enum) { Fn: Fn, BoundFn: Fn, Opaque: void, - Frame: void, + Frame: Frame, AnyFrame: AnyFrame, Vector: Vector, EnumLiteral: void, @@ -315,6 +315,12 @@ pub const TypeInfo = union(enum) { args: []FnArg, }; + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const Frame = struct { + function: var, + }; + /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. pub const AnyFrame = struct { diff --git a/src/ir.cpp b/src/ir.cpp index 0111a33f34..1a7c0c3527 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -25446,10 +25446,18 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI ZigType *child_type = get_const_field_meta_type_optional(ira, source_instr->source_node, payload, "child", 0); return get_any_frame_type(ira->codegen, child_type); } + case ZigTypeIdEnumLiteral: + return ira->codegen->builtin_types.entry_enum_literal; + case ZigTypeIdFnFrame: { + assert(payload->special == ConstValSpecialStatic); + assert(payload->type == ir_type_info_get_type(ira, "Frame", nullptr)); + ZigValue *function = get_const_field(ira, source_instr->source_node, payload, "function", 0); + assert(function->type->id == ZigTypeIdFn); + ZigFn *fn = function->data.x_ptr.data.fn.fn_entry; + return get_fn_frame_type(ira->codegen, fn); + } case ZigTypeIdErrorSet: case ZigTypeIdEnum: - case ZigTypeIdFnFrame: - case ZigTypeIdEnumLiteral: ir_add_error(ira, source_instr, buf_sprintf( "TODO implement @Type for 'TypeInfo.%s': see https://github.com/ziglang/zig/issues/2907", type_id_name(tagTypeId))); return ira->codegen->invalid_inst_gen->value->type; diff --git a/test/stage1/behavior/type.zig b/test/stage1/behavior/type.zig index 2860229cb8..d8ed633887 100644 --- a/test/stage1/behavior/type.zig +++ b/test/stage1/behavior/type.zig @@ -213,3 +213,19 @@ test "Type.AnyFrame" { anyframe->anyframe->u8, }); } + +test "Type.EnumLiteral" { + testTypes(&[_]type{ + @TypeOf(.Dummy), + }); +} + +fn add(a: i32, b: i32) i32 { + return a + b; +} + +test "Type.Frame" { + testTypes(&[_]type{ + @Frame(add), + }); +} -- cgit v1.2.3 From a62e9bc8e50296e2d5b201614a78b0e658887aa9 Mon Sep 17 00:00:00 2001 From: Tadeo Kondrak Date: Thu, 30 Apr 2020 05:50:17 -0600 Subject: Implement @Type for ErrorSet --- lib/std/builtin.zig | 1 + src/ir.cpp | 74 ++++++++++++++++++++++++++++++++++++++++++- test/stage1/behavior/type.zig | 7 ++++ 3 files changed, 81 insertions(+), 1 deletion(-) (limited to 'src/ir.cpp') diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 9b0293228b..47fba9d095 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -256,6 +256,7 @@ pub const TypeInfo = union(enum) { /// therefore must be kept in sync with the compiler implementation. pub const Error = struct { name: []const u8, + /// This field is ignored when using @Type(). value: comptime_int, }; diff --git a/src/ir.cpp b/src/ir.cpp index 1a7c0c3527..5ba92be3c0 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -25456,7 +25456,79 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI ZigFn *fn = function->data.x_ptr.data.fn.fn_entry; return get_fn_frame_type(ira->codegen, fn); } - case ZigTypeIdErrorSet: + case ZigTypeIdErrorSet: { + assert(payload->special == ConstValSpecialStatic); + assert(payload->type->id == ZigTypeIdOptional); + ZigValue *slice = payload->data.x_optional; + if (slice == nullptr) + return ira->codegen->builtin_types.entry_global_error_set; + assert(slice->special == ConstValSpecialStatic); + assert(is_slice(slice->type)); + ZigType *err_set_type = new_type_table_entry(ZigTypeIdErrorSet); + Buf bare_name = BUF_INIT; + buf_init_from_buf(&err_set_type->name, get_anon_type_name(ira->codegen, ira->old_irb.exec, "error", source_instr->scope, source_instr->source_node, &bare_name)); + err_set_type->size_in_bits = ira->codegen->builtin_types.entry_global_error_set->size_in_bits; + err_set_type->abi_align = ira->codegen->builtin_types.entry_global_error_set->abi_align; + err_set_type->abi_size = ira->codegen->builtin_types.entry_global_error_set->abi_size; + ZigValue *ptr = slice->data.x_struct.fields[slice_ptr_index]; + assert(ptr->data.x_ptr.special == ConstPtrSpecialBaseArray);; + assert(ptr->data.x_ptr.data.base_array.elem_index == 0); + ZigValue *arr = ptr->data.x_ptr.data.base_array.array_val; + assert(arr->special == ConstValSpecialStatic); + assert(arr->data.x_array.special == ConstArraySpecialNone); + ZigValue *len = slice->data.x_struct.fields[slice_len_index]; + size_t count = bigint_as_usize(&len->data.x_bigint); + err_set_type->data.error_set.err_count = count; + err_set_type->data.error_set.errors = heap::c_allocator.allocate(count); + bool *already_set = heap::c_allocator.allocate(ira->codegen->errors_by_index.length + count); + for (size_t i = 0; i < count; i++) { + ZigValue *error = &arr->data.x_array.data.s_none.elements[i]; + assert(error->type == ir_type_info_get_type(ira, "Error", nullptr)); + ErrorTableEntry *err_entry = heap::c_allocator.create(); + err_entry->decl_node = source_instr->source_node; + ZigValue *name_slice = get_const_field(ira, source_instr->source_node, error, "name", 0); + ZigValue *name_ptr = name_slice->data.x_struct.fields[slice_ptr_index]; + ZigValue *name_len = name_slice->data.x_struct.fields[slice_len_index]; + assert(name_ptr->data.x_ptr.special == ConstPtrSpecialBaseArray); + assert(name_ptr->data.x_ptr.data.base_array.elem_index == 0); + ZigValue *name_arr = name_ptr->data.x_ptr.data.base_array.array_val; + assert(name_arr->special == ConstValSpecialStatic); + switch (name_arr->data.x_array.special) { + case ConstArraySpecialUndef: + return ira->codegen->invalid_inst_gen->value->type; + case ConstArraySpecialNone: { + buf_resize(&err_entry->name, 0); + size_t name_count = bigint_as_usize(&name_len->data.x_bigint); + for (size_t j = 0; j < name_count; j++) { + ZigValue *ch_val = &name_arr->data.x_array.data.s_none.elements[j]; + unsigned ch = bigint_as_u32(&ch_val->data.x_bigint); + buf_append_char(&err_entry->name, ch); + } + break; + } + case ConstArraySpecialBuf: + buf_init_from_buf(&err_entry->name, name_arr->data.x_array.data.s_buf); + break; + } + auto existing_entry = ira->codegen->error_table.put_unique(&err_entry->name, err_entry); + if (existing_entry) { + err_entry->value = existing_entry->value->value; + } else { + size_t error_value_count = ira->codegen->errors_by_index.length; + assert((uint32_t)error_value_count < (((uint32_t)1) << (uint32_t)ira->codegen->err_tag_type->data.integral.bit_count)); + err_entry->value = error_value_count; + ira->codegen->errors_by_index.append(err_entry); + } + if (already_set[err_entry->value]) { + ir_add_error(ira, source_instr, buf_sprintf("duplicate error: %s", buf_ptr(&err_entry->name))); + return ira->codegen->invalid_inst_gen->value->type; + } else { + already_set[err_entry->value] = true; + } + err_set_type->data.error_set.errors[i] = err_entry; + } + return err_set_type; + } case ZigTypeIdEnum: ir_add_error(ira, source_instr, buf_sprintf( "TODO implement @Type for 'TypeInfo.%s': see https://github.com/ziglang/zig/issues/2907", type_id_name(tagTypeId))); diff --git a/test/stage1/behavior/type.zig b/test/stage1/behavior/type.zig index d8ed633887..f21e9f1ce9 100644 --- a/test/stage1/behavior/type.zig +++ b/test/stage1/behavior/type.zig @@ -229,3 +229,10 @@ test "Type.Frame" { @Frame(add), }); } + +test "Type.ErrorSet" { + // error sets don't compare equal so just check if they compile + _ = @Type(@typeInfo(error{})); + _ = @Type(@typeInfo(error{A})); + _ = @Type(@typeInfo(error{ A, B, C })); +} -- cgit v1.2.3 From 2bb3e1aff4976b2d04fb08a46d9221c77da0b204 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 15 Jun 2020 16:48:19 -0400 Subject: stage1: implement type coercion of anon struct literal to struct closes #3672 --- src/ir.cpp | 146 +++++++++++++++++++++++++++++++++++++--- test/stage1/behavior/struct.zig | 33 +++++++++ 2 files changed, 171 insertions(+), 8 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 887f0a2f9b..d28648e128 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -286,6 +286,7 @@ static IrInstGen *ir_analyze_struct_value_field_value(IrAnalyze *ira, IrInst* so IrInstGen *struct_operand, TypeStructField *field); static bool value_cmp_numeric_val_any(ZigValue *left, Cmp predicate, ZigValue *right); static bool value_cmp_numeric_val_all(ZigValue *left, Cmp predicate, ZigValue *right); +static void memoize_field_init_val(CodeGen *codegen, ZigType *container_type, TypeStructField *field); #define ir_assert(OK, SOURCE_INSTRUCTION) ir_assert_impl((OK), (SOURCE_INSTRUCTION), __FILE__, __LINE__) #define ir_assert_gen(OK, SOURCE_INSTRUCTION) ir_assert_gen_impl((OK), (SOURCE_INSTRUCTION), __FILE__, __LINE__) @@ -14703,10 +14704,139 @@ static IrInstGen *ir_analyze_struct_literal_to_array(IrAnalyze *ira, IrInst* sou } static IrInstGen *ir_analyze_struct_literal_to_struct(IrAnalyze *ira, IrInst* source_instr, - IrInstGen *value, ZigType *wanted_type) + IrInstGen *struct_operand, ZigType *wanted_type) { - ir_add_error(ira, source_instr, buf_sprintf("TODO: type coercion of anon struct literal to struct")); - return ira->codegen->invalid_inst_gen; + Error err; + + IrInstGen *struct_ptr = ir_get_ref(ira, source_instr, struct_operand, true, false); + if (type_is_invalid(struct_ptr->value->type)) + return ira->codegen->invalid_inst_gen; + + if (wanted_type->data.structure.resolve_status == ResolveStatusBeingInferred) { + ir_add_error(ira, source_instr, buf_sprintf("type coercion of anon struct literal to inferred struct")); + return ira->codegen->invalid_inst_gen; + } + + if ((err = type_resolve(ira->codegen, wanted_type, ResolveStatusSizeKnown))) + return ira->codegen->invalid_inst_gen; + + size_t actual_field_count = wanted_type->data.structure.src_field_count; + size_t instr_field_count = struct_operand->value->type->data.structure.src_field_count; + + bool need_comptime = ir_should_inline(ira->old_irb.exec, source_instr->scope) + || type_requires_comptime(ira->codegen, wanted_type) == ReqCompTimeYes; + bool is_comptime = true; + + // Determine if the struct_operand will be comptime. + // Also emit compile errors for missing fields and duplicate fields. + AstNode **field_assign_nodes = heap::c_allocator.allocate(actual_field_count); + ZigValue **field_values = heap::c_allocator.allocate(actual_field_count); + IrInstGen **casted_fields = heap::c_allocator.allocate(actual_field_count); + IrInstGen *const_result = ir_const(ira, source_instr, wanted_type); + + for (size_t i = 0; i < instr_field_count; i += 1) { + TypeStructField *src_field = struct_operand->value->type->data.structure.fields[i]; + TypeStructField *dst_field = find_struct_type_field(wanted_type, src_field->name); + if (dst_field == nullptr) { + ErrorMsg *msg = ir_add_error(ira, source_instr, buf_sprintf("no field named '%s' in struct '%s'", + buf_ptr(src_field->name), buf_ptr(&wanted_type->name))); + if (wanted_type->data.structure.decl_node) { + add_error_note(ira->codegen, msg, wanted_type->data.structure.decl_node, + buf_sprintf("struct '%s' declared here", buf_ptr(&wanted_type->name))); + } + add_error_note(ira->codegen, msg, src_field->decl_node, + buf_sprintf("field '%s' declared here", buf_ptr(src_field->name))); + return ira->codegen->invalid_inst_gen; + } + + ir_assert(src_field->decl_node != nullptr, source_instr); + AstNode *existing_assign_node = field_assign_nodes[dst_field->src_index]; + if (existing_assign_node != nullptr) { + ErrorMsg *msg = ir_add_error(ira, source_instr, buf_sprintf("duplicate field")); + add_error_note(ira->codegen, msg, existing_assign_node, buf_sprintf("other field here")); + return ira->codegen->invalid_inst_gen; + } + field_assign_nodes[dst_field->src_index] = src_field->decl_node; + + IrInstGen *field_ptr = ir_analyze_struct_field_ptr(ira, source_instr, src_field, struct_ptr, + struct_operand->value->type, false); + if (type_is_invalid(field_ptr->value->type)) + return ira->codegen->invalid_inst_gen; + IrInstGen *field_value = ir_get_deref(ira, source_instr, field_ptr, nullptr); + if (type_is_invalid(field_value->value->type)) + return ira->codegen->invalid_inst_gen; + IrInstGen *casted_value = ir_implicit_cast(ira, field_value, dst_field->type_entry); + if (type_is_invalid(casted_value->value->type)) + return ira->codegen->invalid_inst_gen; + + casted_fields[dst_field->src_index] = casted_value; + if (need_comptime || instr_is_comptime(casted_value)) { + ZigValue *field_val = ir_resolve_const(ira, casted_value, UndefOk); + if (field_val == nullptr) + return ira->codegen->invalid_inst_gen; + field_val->parent.id = ConstParentIdStruct; + field_val->parent.data.p_struct.struct_val = const_result->value; + field_val->parent.data.p_struct.field_index = dst_field->src_index; + field_values[dst_field->src_index] = field_val; + } else { + is_comptime = false; + } + } + + bool any_missing = false; + for (size_t i = 0; i < actual_field_count; i += 1) { + if (field_assign_nodes[i] != nullptr) continue; + + // look for a default field value + TypeStructField *field = wanted_type->data.structure.fields[i]; + memoize_field_init_val(ira->codegen, wanted_type, field); + if (field->init_val == nullptr) { + ir_add_error(ira, source_instr, + buf_sprintf("missing field: '%s'", buf_ptr(field->name))); + any_missing = true; + continue; + } + if (type_is_invalid(field->init_val->type)) + return ira->codegen->invalid_inst_gen; + ZigValue *init_val_copy = ira->codegen->pass1_arena->create(); + copy_const_val(ira->codegen, init_val_copy, field->init_val); + init_val_copy->parent.id = ConstParentIdStruct; + init_val_copy->parent.data.p_struct.struct_val = const_result->value; + init_val_copy->parent.data.p_struct.field_index = i; + field_values[i] = init_val_copy; + casted_fields[i] = ir_const_move(ira, source_instr, init_val_copy); + } + if (any_missing) + return ira->codegen->invalid_inst_gen; + + if (is_comptime) { + heap::c_allocator.deallocate(field_assign_nodes, actual_field_count); + IrInstGen *const_result = ir_const(ira, source_instr, wanted_type); + const_result->value->data.x_struct.fields = field_values; + return const_result; + } + + IrInstGen *result_loc_inst = ir_resolve_result(ira, source_instr, no_result_loc(), + wanted_type, nullptr, true, true); + if (type_is_invalid(result_loc_inst->value->type) || result_loc_inst->value->type->id == ZigTypeIdUnreachable) { + return ira->codegen->invalid_inst_gen; + } + + for (size_t i = 0; i < actual_field_count; i += 1) { + TypeStructField *field = wanted_type->data.structure.fields[i]; + IrInstGen *field_ptr = ir_analyze_struct_field_ptr(ira, source_instr, field, result_loc_inst, wanted_type, true); + if (type_is_invalid(field_ptr->value->type)) + return ira->codegen->invalid_inst_gen; + IrInstGen *store_ptr_inst = ir_analyze_store_ptr(ira, source_instr, field_ptr, casted_fields[i], true); + if (type_is_invalid(store_ptr_inst->value->type)) + return ira->codegen->invalid_inst_gen; + } + + heap::c_allocator.deallocate(field_assign_nodes, actual_field_count); + heap::c_allocator.deallocate(field_values, actual_field_count); + heap::c_allocator.deallocate(casted_fields, actual_field_count); + + return ir_get_deref(ira, source_instr, result_loc_inst, nullptr); } static IrInstGen *ir_analyze_struct_literal_to_union(IrAnalyze *ira, IrInst* source_instr, @@ -14727,7 +14857,7 @@ static IrInstGen *ir_analyze_struct_literal_to_union(IrAnalyze *ira, IrInst* sou TypeUnionField *union_field = find_union_type_field(union_type, only_field->name); if (union_field == nullptr) { ir_add_error_node(ira, only_field->decl_node, - buf_sprintf("no member named '%s' in union '%s'", + buf_sprintf("no field named '%s' in union '%s'", buf_ptr(only_field->name), buf_ptr(&union_type->name))); return ira->codegen->invalid_inst_gen; } @@ -22407,7 +22537,7 @@ static IrInstGen *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstSrcFiel usize, ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile, 0); } else { ir_add_error_node(ira, source_node, - buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name), + buf_sprintf("no field named '%s' in '%s'", buf_ptr(field_name), buf_ptr(&container_type->name))); return ira->codegen->invalid_inst_gen; } @@ -23834,7 +23964,7 @@ static IrInstGen *ir_analyze_union_init(IrAnalyze *ira, IrInst* source_instructi TypeUnionField *type_field = find_union_type_field(union_type, field_name); if (type_field == nullptr) { ir_add_error_node(ira, field_source_node, - buf_sprintf("no member named '%s' in union '%s'", + buf_sprintf("no field named '%s' in union '%s'", buf_ptr(field_name), buf_ptr(&union_type->name))); return ira->codegen->invalid_inst_gen; } @@ -23930,7 +24060,7 @@ static IrInstGen *ir_analyze_container_init_fields(IrAnalyze *ira, IrInst *sourc TypeStructField *type_field = find_struct_type_field(container_type, field->name); if (!type_field) { ir_add_error_node(ira, field->source_node, - buf_sprintf("no member named '%s' in struct '%s'", + buf_sprintf("no field named '%s' in struct '%s'", buf_ptr(field->name), buf_ptr(&container_type->name))); return ira->codegen->invalid_inst_gen; } @@ -23965,7 +24095,7 @@ static IrInstGen *ir_analyze_container_init_fields(IrAnalyze *ira, IrInst *sourc memoize_field_init_val(ira->codegen, container_type, field); if (field->init_val == nullptr) { ir_add_error(ira, source_instr, - buf_sprintf("missing field: '%s'", buf_ptr(container_type->data.structure.fields[i]->name))); + buf_sprintf("missing field: '%s'", buf_ptr(field->name))); any_missing = true; continue; } diff --git a/test/stage1/behavior/struct.zig b/test/stage1/behavior/struct.zig index 3a4e0a4d93..7b8690d604 100644 --- a/test/stage1/behavior/struct.zig +++ b/test/stage1/behavior/struct.zig @@ -851,3 +851,36 @@ test "struct with union field" { expectEqual(@as(u32, 2), True.ref); expectEqual(true, True.kind.Bool); } + +test "type coercion of anon struct literal to struct" { + const S = struct { + const S2 = struct { + A: u32, + B: []const u8, + C: void, + D: Foo = .{}, + }; + + const Foo = struct { + field: i32 = 1234, + }; + + fn doTheTest() void { + var y: u32 = 42; + const t0 = .{ .A = 123, .B = "foo", .C = {} }; + const t1 = .{ .A = y, .B = "foo", .C = {} }; + const y0: S2 = t0; + var y1: S2 = t1; + expect(y0.A == 123); + expect(std.mem.eql(u8, y0.B, "foo")); + expect(y0.C == {}); + expect(y0.D.field == 1234); + expect(y1.A == y); + expect(std.mem.eql(u8, y1.B, "foo")); + expect(y1.C == {}); + expect(y1.D.field == 1234); + } + }; + S.doTheTest(); + comptime S.doTheTest(); +} -- cgit v1.2.3 From 04c3fae720b57e72dedbaf28982e7e9bfed47db6 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Mon, 15 Jun 2020 17:04:32 +0200 Subject: Remove obsolete branch in ir_analyze_cast Branch handling `*[N]T` to `E![]T` is already handled in a more complete branch handling `*[N]T` to `[]T` *and* `*[N]T` to `E![]T` so it seems safe to remove this one. --- src/ir.cpp | 40 ---------------------------------------- 1 file changed, 40 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index d28648e128..71e3b473b2 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -15257,46 +15257,6 @@ static IrInstGen *ir_analyze_cast(IrAnalyze *ira, IrInst *source_instr, } } - // *[N]T to E![]T - if (wanted_type->id == ZigTypeIdErrorUnion && - is_slice(wanted_type->data.error_union.payload_type) && - actual_type->id == ZigTypeIdPointer && - actual_type->data.pointer.ptr_len == PtrLenSingle && - actual_type->data.pointer.child_type->id == ZigTypeIdArray) - { - ZigType *slice_type = wanted_type->data.error_union.payload_type; - ZigType *slice_ptr_type = slice_type->data.structure.fields[slice_ptr_index]->type_entry; - assert(slice_ptr_type->id == ZigTypeIdPointer); - ZigType *array_type = actual_type->data.pointer.child_type; - bool const_ok = (slice_ptr_type->data.pointer.is_const || array_type->data.array.len == 0 - || !actual_type->data.pointer.is_const); - if (const_ok && types_match_const_cast_only(ira, slice_ptr_type->data.pointer.child_type, - array_type->data.array.child_type, source_node, - !slice_ptr_type->data.pointer.is_const).id == ConstCastResultIdOk) - { - // If the pointers both have ABI align, it works. - bool ok_align = slice_ptr_type->data.pointer.explicit_alignment == 0 && - actual_type->data.pointer.explicit_alignment == 0; - if (!ok_align) { - // If either one has non ABI align, we have to resolve them both - if ((err = type_resolve(ira->codegen, actual_type->data.pointer.child_type, - ResolveStatusAlignmentKnown))) - { - return ira->codegen->invalid_inst_gen; - } - if ((err = type_resolve(ira->codegen, slice_ptr_type->data.pointer.child_type, - ResolveStatusAlignmentKnown))) - { - return ira->codegen->invalid_inst_gen; - } - ok_align = get_ptr_align(ira->codegen, actual_type) >= get_ptr_align(ira->codegen, slice_ptr_type); - } - if (ok_align) { - return ir_resolve_ptr_of_array_to_slice(ira, source_instr, value, slice_type, nullptr); - } - } - } - // @Vector(N,T1) to @Vector(N,T2) if (actual_type->id == ZigTypeIdVector && wanted_type->id == ZigTypeIdVector) { if (actual_type->data.vector.len == wanted_type->data.vector.len && -- cgit v1.2.3 From 1157ee130732449811294d70021aaafa588d3048 Mon Sep 17 00:00:00 2001 From: antlilja Date: Wed, 17 Jun 2020 17:35:45 +0200 Subject: Improve builtin op support for f128/comptime_float * Add support for fabs, floor, ceil, trunc and round * Add behavior tests --- CMakeLists.txt | 1 + src/ir.cpp | 21 ++++++-- src/softfloat_ext.cpp | 25 +++++++++ src/softfloat_ext.hpp | 9 ++++ test/stage1/behavior/math.zig | 122 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 173 insertions(+), 5 deletions(-) create mode 100644 src/softfloat_ext.cpp create mode 100644 src/softfloat_ext.hpp (limited to 'src/ir.cpp') diff --git a/CMakeLists.txt b/CMakeLists.txt index 8599d01a5d..94219c1631 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -288,6 +288,7 @@ set(ZIG_SOURCES "${CMAKE_SOURCE_DIR}/src/target.cpp" "${CMAKE_SOURCE_DIR}/src/tokenizer.cpp" "${CMAKE_SOURCE_DIR}/src/util.cpp" + "${CMAKE_SOURCE_DIR}/src/softfloat_ext.cpp" "${ZIG_SOURCES_MEM_PROFILE}" ) set(OPTIMIZED_C_SOURCES diff --git a/src/ir.cpp b/src/ir.cpp index d28648e128..8267842671 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -13,6 +13,7 @@ #include "os.hpp" #include "range_set.hpp" #include "softfloat.hpp" +#include "softfloat_ext.hpp" #include "util.hpp" #include "mem_list.hpp" #include "all_types.hpp" @@ -30303,6 +30304,21 @@ static ErrorMsg *ir_eval_float_op(IrAnalyze *ira, IrInst* source_instr, BuiltinF case BuiltinFnIdSqrt: f128M_sqrt(in, out); break; + case BuiltinFnIdFabs: + f128M_abs(in, out); + break; + case BuiltinFnIdFloor: + f128M_roundToInt(in, softfloat_round_min, false, out); + break; + case BuiltinFnIdCeil: + f128M_roundToInt(in, softfloat_round_max, false, out); + break; + case BuiltinFnIdTrunc: + f128M_trunc(in, out); + break; + case BuiltinFnIdRound: + f128M_roundToInt(in, softfloat_round_near_maxMag, false, out); + break; case BuiltinFnIdNearbyInt: case BuiltinFnIdSin: case BuiltinFnIdCos: @@ -30311,11 +30327,6 @@ static ErrorMsg *ir_eval_float_op(IrAnalyze *ira, IrInst* source_instr, BuiltinF case BuiltinFnIdLog: case BuiltinFnIdLog10: case BuiltinFnIdLog2: - case BuiltinFnIdFabs: - case BuiltinFnIdFloor: - case BuiltinFnIdCeil: - case BuiltinFnIdTrunc: - case BuiltinFnIdRound: return ir_add_error(ira, source_instr, buf_sprintf("compiler bug: TODO: implement '%s' for type '%s'. See https://github.com/ziglang/zig/issues/4026", float_op_to_name(fop), buf_ptr(&float_type->name))); diff --git a/src/softfloat_ext.cpp b/src/softfloat_ext.cpp new file mode 100644 index 0000000000..8408a15116 --- /dev/null +++ b/src/softfloat_ext.cpp @@ -0,0 +1,25 @@ +#include "softfloat_ext.hpp" + +extern "C" { + #include "softfloat.h" +} + +void f128M_abs(const float128_t *aPtr, float128_t *zPtr) { + float128_t zero_float; + ui32_to_f128M(0, &zero_float); + if (f128M_lt(aPtr, &zero_float)) { + f128M_sub(&zero_float, aPtr, zPtr); + } else { + *zPtr = *aPtr; + } +} + +void f128M_trunc(const float128_t *aPtr, float128_t *zPtr) { + float128_t zero_float; + ui32_to_f128M(0, &zero_float); + if (f128M_lt(aPtr, &zero_float)) { + f128M_roundToInt(aPtr, softfloat_round_max, false, zPtr); + } else { + f128M_roundToInt(aPtr, softfloat_round_min, false, zPtr); + } +} \ No newline at end of file diff --git a/src/softfloat_ext.hpp b/src/softfloat_ext.hpp new file mode 100644 index 0000000000..0a1f958933 --- /dev/null +++ b/src/softfloat_ext.hpp @@ -0,0 +1,9 @@ +#ifndef ZIG_SOFTFLOAT_EXT_HPP +#define ZIG_SOFTFLOAT_EXT_HPP + +#include "softfloat_types.h" + +void f128M_abs(const float128_t *aPtr, float128_t *zPtr); +void f128M_trunc(const float128_t *aPtr, float128_t *zPtr); + +#endif \ No newline at end of file diff --git a/test/stage1/behavior/math.zig b/test/stage1/behavior/math.zig index 1d361494eb..b13b1ce1e0 100644 --- a/test/stage1/behavior/math.zig +++ b/test/stage1/behavior/math.zig @@ -634,6 +634,128 @@ fn testSqrt(comptime T: type, x: T) void { expect(@sqrt(x * x) == x); } +test "@fabs" { + testFabs(f128, 12.0); + comptime testFabs(f128, 12.0); + testFabs(f64, 12.0); + comptime testFabs(f64, 12.0); + testFabs(f32, 12.0); + comptime testFabs(f32, 12.0); + testFabs(f16, 12.0); + comptime testFabs(f16, 12.0); + + const x = 14.0; + const y = -x; + const z = @fabs(y); + comptime expectEqual(x, z); +} + +fn testFabs(comptime T: type, x: T) void { + const y = -x; + const z = @fabs(y); + expectEqual(x, z); +} + +test "@floor" { + // FIXME: Generates a floorl function call + // testFloor(f128, 12.0); + comptime testFloor(f128, 12.0); + testFloor(f64, 12.0); + comptime testFloor(f64, 12.0); + testFloor(f32, 12.0); + comptime testFloor(f32, 12.0); + testFloor(f16, 12.0); + comptime testFloor(f16, 12.0); + + const x = 14.0; + const y = x + 0.7; + const z = @floor(y); + comptime expectEqual(x, z); +} + +fn testFloor(comptime T: type, x: T) void { + const y = x + 0.6; + const z = @floor(y); + expectEqual(x, z); +} + +test "@ceil" { + // FIXME: Generates a ceill function call + //testCeil(f128, 12.0); + comptime testCeil(f128, 12.0); + testCeil(f64, 12.0); + comptime testCeil(f64, 12.0); + testCeil(f32, 12.0); + comptime testCeil(f32, 12.0); + testCeil(f16, 12.0); + comptime testCeil(f16, 12.0); + + const x = 14.0; + const y = x - 0.7; + const z = @ceil(y); + comptime expectEqual(x, z); +} + +fn testCeil(comptime T: type, x: T) void { + const y = x - 0.8; + const z = @ceil(y); + expectEqual(x, z); +} + +test "@trunc" { + // FIXME: Generates a truncl function call + //testTrunc(f128, 12.0); + comptime testTrunc(f128, 12.0); + testTrunc(f64, 12.0); + comptime testTrunc(f64, 12.0); + testTrunc(f32, 12.0); + comptime testTrunc(f32, 12.0); + testTrunc(f16, 12.0); + comptime testTrunc(f16, 12.0); + + const x = 14.0; + const y = x + 0.7; + const z = @trunc(y); + comptime expectEqual(x, z); +} + +fn testTrunc(comptime T: type, x: T) void { + { + const y = x + 0.8; + const z = @trunc(y); + expectEqual(x, z); + } + + { + const y = -x - 0.8; + const z = @trunc(y); + expectEqual(-x, z); + } +} + +test "@round" { + // FIXME: Generates a roundl function call + //testRound(f128, 12.0); + comptime testRound(f128, 12.0); + testRound(f64, 12.0); + comptime testRound(f64, 12.0); + testRound(f32, 12.0); + comptime testRound(f32, 12.0); + testRound(f16, 12.0); + comptime testRound(f16, 12.0); + + const x = 14.0; + const y = x + 0.4; + const z = @round(y); + comptime expectEqual(x, z); +} + +fn testRound(comptime T: type, x: T) void { + const y = x - 0.5; + const z = @round(y); + expectEqual(x, z); +} + test "comptime_int param and return" { const a = comptimeAdd(35361831660712422535336160538497375248, 101752735581729509668353361206450473702); expect(a == 137114567242441932203689521744947848950); -- cgit v1.2.3 From a5379aa3ee376197820f1526c88921607a787a11 Mon Sep 17 00:00:00 2001 From: Vexu Date: Thu, 18 Jun 2020 20:45:48 +0300 Subject: implement `@src` --- lib/std/builtin.zig | 9 +++++++ src/all_types.hpp | 6 +++++ src/codegen.cpp | 1 + src/ir.cpp | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/ir_print.cpp | 9 +++++++ 5 files changed, 101 insertions(+) (limited to 'src/ir.cpp') diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index af8033ae91..822901be73 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -131,6 +131,15 @@ pub const CallingConvention = enum { AAPCSVFP, }; +/// This data structure is used by the Zig language code generation and +/// therefore must be kept in sync with the compiler implementation. +pub const SourceLocation = struct { + file: []const u8, + fn_name: []const u8, + line: u32, + column: u32, +}; + pub const TypeId = @TagType(TypeInfo); /// This data structure is used by the Zig language code generation and diff --git a/src/all_types.hpp b/src/all_types.hpp index 9413ea73a4..88c7e96943 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1827,6 +1827,7 @@ enum BuiltinFnId { BuiltinFnIdBitSizeof, BuiltinFnIdWasmMemorySize, BuiltinFnIdWasmMemoryGrow, + BuiltinFnIdSrc, }; struct BuiltinFnEntry { @@ -2754,6 +2755,7 @@ enum IrInstSrcId { IrInstSrcIdSpillEnd, IrInstSrcIdWasmMemorySize, IrInstSrcIdWasmMemoryGrow, + IrInstSrcIdSrc, }; // ir_render_* functions in codegen.cpp consume Gen instructions and produce LLVM IR. @@ -3761,6 +3763,10 @@ struct IrInstGenWasmMemoryGrow { IrInstGen *delta; }; +struct IrInstSrcSrc { + IrInstSrc base; +}; + struct IrInstSrcSlice { IrInstSrc base; diff --git a/src/codegen.cpp b/src/codegen.cpp index f945dd6545..e20d6d60f5 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -8714,6 +8714,7 @@ static void define_builtin_fns(CodeGen *g) { create_builtin_fn(g, BuiltinFnIdBitSizeof, "bitSizeOf", 1); create_builtin_fn(g, BuiltinFnIdWasmMemorySize, "wasmMemorySize", 1); create_builtin_fn(g, BuiltinFnIdWasmMemoryGrow, "wasmMemoryGrow", 2); + create_builtin_fn(g, BuiltinFnIdSrc, "src", 0); } static const char *bool_to_str(bool b) { diff --git a/src/ir.cpp b/src/ir.cpp index 71e3b473b2..6406458bf5 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -561,6 +561,8 @@ static void destroy_instruction_src(IrInstSrc *inst) { return heap::c_allocator.destroy(reinterpret_cast(inst)); case IrInstSrcIdWasmMemoryGrow: return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdSrc: + return heap::c_allocator.destroy(reinterpret_cast(inst)); } zig_unreachable(); } @@ -1627,6 +1629,9 @@ static constexpr IrInstSrcId ir_inst_id(IrInstSrcWasmMemoryGrow *) { return IrInstSrcIdWasmMemoryGrow; } +static constexpr IrInstSrcId ir_inst_id(IrInstSrcSrc *) { + return IrInstSrcIdSrc; +} static constexpr IrInstGenId ir_inst_id(IrInstGenDeclVar *) { return IrInstGenIdDeclVar; @@ -5030,6 +5035,11 @@ static IrInstGen *ir_build_wasm_memory_grow_gen(IrAnalyze *ira, IrInst *source_i return &instruction->base; } +static IrInstSrc *ir_build_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) { + IrInstSrcSrc *instruction = ir_build_instruction(irb, scope, source_node); + + return &instruction->base; +} static void ir_count_defers(IrBuilderSrc *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) { results[ReturnKindUnconditional] = 0; @@ -7450,6 +7460,11 @@ static IrInstSrc *ir_gen_builtin_fn_call(IrBuilderSrc *irb, Scope *scope, AstNod return ir_gen_union_init_expr(irb, scope, node, union_type_inst, name_inst, init_node, lval, result_loc); } + case BuiltinFnIdSrc: + { + IrInstSrc *src_inst = ir_build_src(irb, scope, node); + return ir_lval_wrap(irb, scope, src_inst, lval, result_loc); + } } zig_unreachable(); } @@ -30859,6 +30874,64 @@ static IrInstGen *ir_analyze_instruction_spill_end(IrAnalyze *ira, IrInstSrcSpil return ir_build_spill_end_gen(ira, &instruction->base.base, begin, operand->value->type); } +static IrInstGen *ir_analyze_instruction_src(IrAnalyze *ira, IrInstSrcSrc *instruction) { + ZigFn *fn_entry = scope_fn_entry(instruction->base.base.scope); + if (fn_entry == nullptr) { + ir_add_error(ira, &instruction->base.base, buf_sprintf("@src outside function")); + return ira->codegen->invalid_inst_gen; + } + + ZigType *u8_ptr = get_pointer_to_type_extra( + ira->codegen, ira->codegen->builtin_types.entry_u8, + true, false, PtrLenUnknown, + 0, 0, 0, false); + ZigType *u8_slice = get_slice_type(ira->codegen, u8_ptr); + + ZigType *source_location_type = get_builtin_type(ira->codegen, "SourceLocation"); + if (type_resolve(ira->codegen, source_location_type, ResolveStatusSizeKnown)) { + zig_unreachable(); + } + + ZigValue *result = ira->codegen->pass1_arena->create(); + result->special = ConstValSpecialStatic; + result->type = source_location_type; + + ZigValue **fields = alloc_const_vals_ptrs(ira->codegen, 4); + result->data.x_struct.fields = fields; + + // file: []const u8 + ensure_field_index(source_location_type, "file", 0); + fields[0]->special = ConstValSpecialStatic; + fields[0]->type = u8_slice; + + ZigType *import = instruction->base.base.source_node->owner; + Buf *path = import->data.structure.root_struct->path; + ZigValue *file_name = create_const_str_lit(ira->codegen, path)->data.x_ptr.data.ref.pointee; + init_const_slice(ira->codegen, fields[0], file_name, 0, buf_len(path), true); + + // fn_name: []const u8 + ensure_field_index(source_location_type, "fn_name", 1); + fields[1]->special = ConstValSpecialStatic; + fields[1]->type = u8_slice; + + ZigValue *fn_name = create_const_str_lit(ira->codegen, &fn_entry->symbol_name)->data.x_ptr.data.ref.pointee; + init_const_slice(ira->codegen, fields[1], fn_name, 0, buf_len(&fn_entry->symbol_name), true); + + // line: u32 + ensure_field_index(source_location_type, "line", 2); + fields[2]->special = ConstValSpecialStatic; + fields[2]->type = ira->codegen->builtin_types.entry_u32; + bigint_init_unsigned(&fields[2]->data.x_bigint, instruction->base.base.source_node->line + 1); + + // column: u32 + ensure_field_index(source_location_type, "column", 3); + fields[3]->special = ConstValSpecialStatic; + fields[3]->type = ira->codegen->builtin_types.entry_u32; + bigint_init_unsigned(&fields[3]->data.x_bigint, instruction->base.base.source_node->column + 1); + + return ir_const_move(ira, &instruction->base.base, result); +} + static IrInstGen *ir_analyze_instruction_base(IrAnalyze *ira, IrInstSrc *instruction) { switch (instruction->id) { case IrInstSrcIdInvalid: @@ -31130,6 +31203,8 @@ static IrInstGen *ir_analyze_instruction_base(IrAnalyze *ira, IrInstSrc *instruc return ir_analyze_instruction_wasm_memory_size(ira, (IrInstSrcWasmMemorySize *)instruction); case IrInstSrcIdWasmMemoryGrow: return ir_analyze_instruction_wasm_memory_grow(ira, (IrInstSrcWasmMemoryGrow *)instruction); + case IrInstSrcIdSrc: + return ir_analyze_instruction_src(ira, (IrInstSrcSrc *)instruction); } zig_unreachable(); } @@ -31525,6 +31600,7 @@ bool ir_inst_src_has_side_effects(IrInstSrc *instruction) { case IrInstSrcIdAlloca: case IrInstSrcIdSpillEnd: case IrInstSrcIdWasmMemorySize: + case IrInstSrcIdSrc: return false; case IrInstSrcIdAsm: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index c826d76e03..27bedff47f 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -325,6 +325,8 @@ const char* ir_inst_src_type_str(IrInstSrcId id) { return "SrcWasmMemorySize"; case IrInstSrcIdWasmMemoryGrow: return "SrcWasmMemoryGrow"; + case IrInstSrcIdSrc: + return "SrcSrc"; } zig_unreachable(); } @@ -1744,6 +1746,10 @@ static void ir_print_wasm_memory_grow(IrPrintGen *irp, IrInstGenWasmMemoryGrow * fprintf(irp->f, ")"); } +static void ir_print_builtin_src(IrPrintSrc *irp, IrInstSrcSrc *instruction) { + fprintf(irp->f, "@src()"); +} + static void ir_print_memset(IrPrintSrc *irp, IrInstSrcMemset *instruction) { fprintf(irp->f, "@memset("); ir_print_other_inst_src(irp, instruction->dest_ptr); @@ -2994,6 +3000,9 @@ static void ir_print_inst_src(IrPrintSrc *irp, IrInstSrc *instruction, bool trai case IrInstSrcIdWasmMemoryGrow: ir_print_wasm_memory_grow(irp, (IrInstSrcWasmMemoryGrow *)instruction); break; + case IrInstSrcIdSrc: + ir_print_builtin_src(irp, (IrInstSrcSrc *)instruction); + break; } fprintf(irp->f, "\n"); } -- cgit v1.2.3 From 4a387996311a025a021409f08a61bab9e9885987 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 18 Jun 2020 17:09:10 -0400 Subject: make file and fn_name fields of SourceLocation also null-terminated One of the main motivating use cases for this language feature is tracing/profiling tools, which expect null-terminated strings for these values. Since the data is statically allocated, making them additionally null-terminated comes at no cost. This prevents the requirement of compile-time code to convert to null-termination, which could increase the compilation time of code with tracing enabled. See #2029 --- lib/std/builtin.zig | 4 ++-- src/ir.cpp | 12 ++++++------ test/stage1/behavior/src.zig | 2 ++ 3 files changed, 10 insertions(+), 8 deletions(-) (limited to 'src/ir.cpp') diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 822901be73..195b301840 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -134,8 +134,8 @@ pub const CallingConvention = enum { /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. pub const SourceLocation = struct { - file: []const u8, - fn_name: []const u8, + file: [:0]const u8, + fn_name: [:0]const u8, line: u32, column: u32, }; diff --git a/src/ir.cpp b/src/ir.cpp index 6406458bf5..48e5db8f28 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -30881,10 +30881,10 @@ static IrInstGen *ir_analyze_instruction_src(IrAnalyze *ira, IrInstSrcSrc *instr return ira->codegen->invalid_inst_gen; } - ZigType *u8_ptr = get_pointer_to_type_extra( + ZigType *u8_ptr = get_pointer_to_type_extra2( ira->codegen, ira->codegen->builtin_types.entry_u8, true, false, PtrLenUnknown, - 0, 0, 0, false); + 0, 0, 0, false, VECTOR_INDEX_NONE, nullptr, ira->codegen->intern.for_zero_byte()); ZigType *u8_slice = get_slice_type(ira->codegen, u8_ptr); ZigType *source_location_type = get_builtin_type(ira->codegen, "SourceLocation"); @@ -30899,23 +30899,23 @@ static IrInstGen *ir_analyze_instruction_src(IrAnalyze *ira, IrInstSrcSrc *instr ZigValue **fields = alloc_const_vals_ptrs(ira->codegen, 4); result->data.x_struct.fields = fields; - // file: []const u8 + // file: [:0]const u8 ensure_field_index(source_location_type, "file", 0); fields[0]->special = ConstValSpecialStatic; - fields[0]->type = u8_slice; ZigType *import = instruction->base.base.source_node->owner; Buf *path = import->data.structure.root_struct->path; ZigValue *file_name = create_const_str_lit(ira->codegen, path)->data.x_ptr.data.ref.pointee; init_const_slice(ira->codegen, fields[0], file_name, 0, buf_len(path), true); + fields[0]->type = u8_slice; - // fn_name: []const u8 + // fn_name: [:0]const u8 ensure_field_index(source_location_type, "fn_name", 1); fields[1]->special = ConstValSpecialStatic; - fields[1]->type = u8_slice; ZigValue *fn_name = create_const_str_lit(ira->codegen, &fn_entry->symbol_name)->data.x_ptr.data.ref.pointee; init_const_slice(ira->codegen, fields[1], fn_name, 0, buf_len(&fn_entry->symbol_name), true); + fields[1]->type = u8_slice; // line: u32 ensure_field_index(source_location_type, "line", 2); diff --git a/test/stage1/behavior/src.zig b/test/stage1/behavior/src.zig index eec1154374..27fa144e54 100644 --- a/test/stage1/behavior/src.zig +++ b/test/stage1/behavior/src.zig @@ -12,4 +12,6 @@ fn doTheTest() void { expect(src.column == 17); expect(std.mem.endsWith(u8, src.fn_name, "doTheTest")); expect(std.mem.endsWith(u8, src.file, "src.zig")); + expect(src.fn_name[src.fn_name.len] == 0); + expect(src.file[src.file.len] == 0); } -- cgit v1.2.3 From 8696e52a3d617ce30ec6202adc89cb10c67bcc43 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Sun, 21 Jun 2020 20:55:44 +0200 Subject: Make unary minus for unsigned types a compile error (#5654) * Make unary minus for unsigned types a compile error * Add unreachable when generating unsigned negate --- src/codegen.cpp | 12 ++++++------ src/ir.cpp | 37 ++++++++++++++++++++++--------------- test/compile_errors.zig | 9 +++++++++ 3 files changed, 37 insertions(+), 21 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index e20d6d60f5..f7c3575f86 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3540,7 +3540,7 @@ static LLVMValueRef ir_render_int_to_enum(CodeGen *g, IrExecutableGen *executabl for (size_t field_i = 0; field_i < field_count; field_i += 1) { TypeEnumField *type_enum_field = &wanted_type->data.enumeration.fields[field_i]; - + Buf *name = type_enum_field->name; auto entry = occupied_tag_values.put_unique(type_enum_field->value, name); if (entry != nullptr) { @@ -3654,7 +3654,7 @@ static LLVMValueRef ir_gen_negation(CodeGen *g, IrInstGen *inst, IrInstGen *oper } else if (scalar_type->data.integral.is_signed) { return LLVMBuildNSWNeg(g->builder, llvm_operand, ""); } else { - return LLVMBuildNUWNeg(g->builder, llvm_operand, ""); + zig_unreachable(); } } else { zig_unreachable(); @@ -3984,7 +3984,7 @@ static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutableGen *executable, assert(array_type->data.pointer.child_type->id == ZigTypeIdArray); array_type = array_type->data.pointer.child_type; } - + assert(array_type->data.array.len != 0 || array_type->data.array.sentinel != nullptr); if (safety_check_on) { @@ -5258,7 +5258,7 @@ static LLVMValueRef get_enum_tag_name_function(CodeGen *g, ZigType *enum_type) { for (size_t field_i = 0; field_i < field_count; field_i += 1) { TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[field_i]; - + Buf *name = type_enum_field->name; auto entry = occupied_tag_values.put_unique(type_enum_field->value, name); if (entry != nullptr) { @@ -5471,7 +5471,7 @@ static LLVMTypeRef get_atomic_abi_type(CodeGen *g, IrInstGen *instruction) { } auto bit_count = operand_type->data.integral.bit_count; bool is_signed = operand_type->data.integral.is_signed; - + ir_assert(bit_count != 0, instruction); if (bit_count == 1 || !is_power_of_2(bit_count)) { return get_llvm_type(g, get_int_type(g, is_signed, operand_type->abi_size * 8)); @@ -9265,7 +9265,7 @@ static void init(CodeGen *g) { abi_name = (g->zig_target->arch == ZigLLVM_riscv32) ? "ilp32" : "lp64"; } } - + g->target_machine = ZigLLVMCreateTargetMachine(target_ref, buf_ptr(&g->llvm_triple_str), target_specific_cpu_args, target_specific_features, opt_level, reloc_mode, to_llvm_code_model(g), g->function_sections, float_abi, abi_name); diff --git a/src/ir.cpp b/src/ir.cpp index 635af397c4..bb6ca554df 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -12602,28 +12602,28 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT if (prev_type->id == ZigTypeIdPointer && prev_type->data.pointer.ptr_len == PtrLenSingle && prev_type->data.pointer.child_type->id == ZigTypeIdArray && - ((cur_type->id == ZigTypeIdPointer && cur_type->data.pointer.ptr_len == PtrLenUnknown))) + ((cur_type->id == ZigTypeIdPointer && cur_type->data.pointer.ptr_len == PtrLenUnknown))) { - prev_inst = cur_inst; + prev_inst = cur_inst; if (prev_type->data.pointer.is_const && !cur_type->data.pointer.is_const) { // const array pointer and non-const unknown pointer make_the_pointer_const = true; } - continue; + continue; } // *[N]T to [*]T if (cur_type->id == ZigTypeIdPointer && cur_type->data.pointer.ptr_len == PtrLenSingle && cur_type->data.pointer.child_type->id == ZigTypeIdArray && - ((prev_type->id == ZigTypeIdPointer && prev_type->data.pointer.ptr_len == PtrLenUnknown))) + ((prev_type->id == ZigTypeIdPointer && prev_type->data.pointer.ptr_len == PtrLenUnknown))) { if (cur_type->data.pointer.is_const && !prev_type->data.pointer.is_const) { // const array pointer and non-const unknown pointer make_the_pointer_const = true; } - continue; + continue; } // *[N]T to []T @@ -20987,17 +20987,24 @@ static IrInstGen *ir_analyze_negation(IrAnalyze *ira, IrInstSrcUnOp *instruction if (type_is_invalid(expr_type)) return ira->codegen->invalid_inst_gen; - if (!(expr_type->id == ZigTypeIdInt || expr_type->id == ZigTypeIdComptimeInt || - expr_type->id == ZigTypeIdFloat || expr_type->id == ZigTypeIdComptimeFloat || - expr_type->id == ZigTypeIdVector)) - { - ir_add_error(ira, &instruction->base.base, - buf_sprintf("negation of type '%s'", buf_ptr(&expr_type->name))); - return ira->codegen->invalid_inst_gen; - } - bool is_wrap_op = (instruction->op_id == IrUnOpNegationWrap); + switch (expr_type->id) { + case ZigTypeIdComptimeInt: + case ZigTypeIdFloat: + case ZigTypeIdComptimeFloat: + case ZigTypeIdVector: + break; + case ZigTypeIdInt: + if (is_wrap_op || expr_type->data.integral.is_signed) + break; + ZIG_FALLTHROUGH; + default: + ir_add_error(ira, &instruction->base.base, + buf_sprintf("negation of type '%s'", buf_ptr(&expr_type->name))); + return ira->codegen->invalid_inst_gen; + } + ZigType *scalar_type = (expr_type->id == ZigTypeIdVector) ? expr_type->data.vector.elem_type : expr_type; if (instr_is_comptime(value)) { @@ -30380,7 +30387,7 @@ static ErrorMsg *ir_eval_float_op(IrAnalyze *ira, IrInst* source_instr, BuiltinF case BuiltinFnIdTrunc: f128M_trunc(in, out); break; - case BuiltinFnIdRound: + case BuiltinFnIdRound: f128M_roundToInt(in, softfloat_round_near_maxMag, false, out); break; case BuiltinFnIdNearbyInt: diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 3f898cc337..e3dd1f0d8f 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -7530,4 +7530,13 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { , &[_][]const u8{ "tmp.zig:2:9: error: @wasmMemoryGrow is a wasm32 feature only", }); + + cases.add("Issue #5586: Make unary minus for unsigned types a compile error", + \\export fn f(x: u32) u32 { + \\ const y = -%x; + \\ return -y; + \\} + , &[_][]const u8{ + "tmp.zig:3:12: error: negation of type 'u32'" + }); } -- cgit v1.2.3 From d907f574e02aadf8196e616bcc2fb2813cf2c82c Mon Sep 17 00:00:00 2001 From: xackus <14938807+xackus@users.noreply.github.com> Date: Sat, 20 Jun 2020 18:35:01 +0200 Subject: stage1: fix concat of sliced str literals --- src/ir.cpp | 3 +-- test/stage1/behavior/slice.zig | 5 +++++ 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index bb6ca554df..3fa138ed8e 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -826,12 +826,11 @@ static ZigValue *const_ptr_pointee_unchecked_no_isf(CodeGen *g, ZigValue *const_ ZigValue *array_val = const_val->data.x_ptr.data.base_array.array_val; size_t elem_index = const_val->data.x_ptr.data.base_array.elem_index; - // TODO handle sentinel terminated arrays expand_undef_array(g, array_val); result = g->pass1_arena->create(); result->special = array_val->special; result->type = get_array_type(g, array_val->type->data.array.child_type, - array_val->type->data.array.len - elem_index, nullptr); + array_val->type->data.array.len - elem_index, array_val->type->data.array.sentinel); result->data.x_array.special = ConstArraySpecialNone; result->data.x_array.data.s_none.elements = &array_val->data.x_array.data.s_none.elements[elem_index]; result->parent.id = ConstParentIdArray; diff --git a/test/stage1/behavior/slice.zig b/test/stage1/behavior/slice.zig index 1faefe6800..8aa3bdb7c1 100644 --- a/test/stage1/behavior/slice.zig +++ b/test/stage1/behavior/slice.zig @@ -280,6 +280,11 @@ test "slice syntax resulting in pointer-to-array" { expect(slice[0] == 5); comptime expect(@TypeOf(src_slice[0..2]) == *align(4) [2]u8); } + + fn testConcatStrLiterals() void { + expectEqualSlices("a"[0..] ++ "b"[0..], "ab"); + expectEqualSlices("a"[0..:0] ++ "b"[0..:0], "ab"); + } }; S.doTheTest(); -- cgit v1.2.3 From 0de35af98b3404f0cf7cd9497f661239d197bbbf Mon Sep 17 00:00:00 2001 From: antlilja Date: Mon, 22 Jun 2020 12:14:52 +0200 Subject: Add duplicate checking for switch on types * Add compile error tests --- src/ir.cpp | 32 +++++++++++++++++++++++++++++++- test/compile_errors.zig | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 3fa138ed8e..01c7936f75 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -28861,7 +28861,37 @@ static IrInstGen *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira, ir_add_error(ira, &instruction->base.base, buf_sprintf("else prong required when switching on type '%s'", buf_ptr(&switch_type->name))); return ira->codegen->invalid_inst_gen; - } + } else if(switch_type->id == ZigTypeIdMetaType) { + HashMap prevs; + // HashMap doubles capacity when reaching 60% capacity, + // because we know the size at init we can avoid reallocation by doubling it here + prevs.init(instruction->range_count * 2); + for (size_t range_i = 0; range_i < instruction->range_count; range_i += 1) { + IrInstSrcCheckSwitchProngsRange *range = &instruction->ranges[range_i]; + + IrInstGen *value = range->start->child; + IrInstGen *casted_value = ir_implicit_cast(ira, value, switch_type); + if (type_is_invalid(casted_value->value->type)) { + prevs.deinit(); + return ira->codegen->invalid_inst_gen; + } + + ZigValue *const_expr_val = ir_resolve_const(ira, casted_value, UndefBad); + if (!const_expr_val) { + prevs.deinit(); + return ira->codegen->invalid_inst_gen; + } + + auto entry = prevs.put_unique(const_expr_val->data.x_type, value); + if(entry != nullptr) { + ErrorMsg *msg = ir_add_error(ira, &value->base, buf_sprintf("duplicate switch value")); + add_error_note(ira->codegen, msg, entry->value->base.source_node, buf_sprintf("previous value is here")); + prevs.deinit(); + return ira->codegen->invalid_inst_gen; + } + } + prevs.deinit(); + } return ir_const_void(ira, &instruction->base.base); } diff --git a/test/compile_errors.zig b/test/compile_errors.zig index e3dd1f0d8f..e8b7e610ee 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -4362,6 +4362,40 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:5:14: note: previous value is here", }); + cases.add("switch expression - duplicate type", + \\fn foo(comptime T: type, x: T) u8 { + \\ return switch (T) { + \\ u32 => 0, + \\ u64 => 1, + \\ u32 => 2, + \\ else => 3, + \\ }; + \\} + \\export fn entry() usize { return @sizeOf(@TypeOf(foo(u32, 0))); } + , &[_][]const u8{ + "tmp.zig:5:9: error: duplicate switch value", + "tmp.zig:3:9: note: previous value is here", + }); + + cases.add("switch expression - duplicate type (struct alias)", + \\const Test = struct { + \\ bar: i32, + \\}; + \\const Test2 = Test; + \\fn foo(comptime T: type, x: T) u8 { + \\ return switch (T) { + \\ Test => 0, + \\ u64 => 1, + \\ Test2 => 2, + \\ else => 3, + \\ }; + \\} + \\export fn entry() usize { return @sizeOf(@TypeOf(foo(u32, 0))); } + , &[_][]const u8{ + "tmp.zig:9:9: error: duplicate switch value", + "tmp.zig:7:9: note: previous value is here", + }); + cases.add("switch expression - switch on pointer type with no else", \\fn foo(x: *u8) void { \\ switch (x) { -- cgit v1.2.3 From 50b70bd77f31bba6ffca33b6acb90186e739118e Mon Sep 17 00:00:00 2001 From: Alexandros Naskos Date: Wed, 24 Jun 2020 14:07:39 +0300 Subject: @asyncCall now requires an argument tuple --- lib/std/dwarf.zig | 2 +- lib/std/special/test_runner.zig | 2 +- lib/std/start.zig | 2 +- src/all_types.hpp | 15 ++++ src/ir.cpp | 165 ++++++++++++++++++++++++++++++++-------- src/ir_print.cpp | 109 +++++++++++++------------- 6 files changed, 208 insertions(+), 87 deletions(-) (limited to 'src/ir.cpp') diff --git a/lib/std/dwarf.zig b/lib/std/dwarf.zig index ebb4c096f8..24792c7ca0 100644 --- a/lib/std/dwarf.zig +++ b/lib/std/dwarf.zig @@ -359,7 +359,7 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, endia const F = @TypeOf(async parseFormValue(allocator, in_stream, child_form_id, endian, is_64)); var frame = try allocator.create(F); defer allocator.destroy(frame); - return await @asyncCall(frame, {}, parseFormValue, allocator, in_stream, child_form_id, endian, is_64); + return await @asyncCall(frame, {}, parseFormValue, .{ allocator, in_stream, child_form_id, endian, is_64 }); }, else => error.InvalidDebugInfo, }; diff --git a/lib/std/special/test_runner.zig b/lib/std/special/test_runner.zig index 7403cca9c2..828d3165db 100644 --- a/lib/std/special/test_runner.zig +++ b/lib/std/special/test_runner.zig @@ -35,7 +35,7 @@ pub fn main() anyerror!void { async_frame_buffer = try std.heap.page_allocator.alignedAlloc(u8, std.Target.stack_align, size); } const casted_fn = @ptrCast(fn () callconv(.Async) anyerror!void, test_fn.func); - break :blk await @asyncCall(async_frame_buffer, {}, casted_fn); + break :blk await @asyncCall(async_frame_buffer, {}, casted_fn, .{}); }, .blocking => { skip_count += 1; diff --git a/lib/std/start.zig b/lib/std/start.zig index 604c22101c..811e05012f 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -214,7 +214,7 @@ inline fn initEventLoopAndCallMain() u8 { var result: u8 = undefined; var frame: @Frame(callMainAsync) = undefined; - _ = @asyncCall(&frame, &result, callMainAsync, loop); + _ = @asyncCall(&frame, &result, callMainAsync, .{loop}); loop.run(); return result; } diff --git a/src/all_types.hpp b/src/all_types.hpp index 88c7e96943..4465bf674c 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2641,6 +2641,7 @@ enum IrInstSrcId { IrInstSrcIdCall, IrInstSrcIdCallArgs, IrInstSrcIdCallExtra, + IrInstSrcIdAsyncCallExtra, IrInstSrcIdConst, IrInstSrcIdReturn, IrInstSrcIdContainerInitList, @@ -3255,6 +3256,20 @@ struct IrInstSrcCallExtra { ResultLoc *result_loc; }; +// This is a pass1 instruction, used by @asyncCall, when the args node +// is not a literal. +// `args` is expected to be either a struct or a tuple. +struct IrInstSrcAsyncCallExtra { + IrInstSrc base; + + CallModifier modifier; + IrInstSrc *fn_ref; + IrInstSrc *ret_ptr; + IrInstSrc *new_stack; + IrInstSrc *args; + ResultLoc *result_loc; +}; + struct IrInstGenCall { IrInstGen base; diff --git a/src/ir.cpp b/src/ir.cpp index 01c7936f75..b765ea09ff 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -310,6 +310,8 @@ static void destroy_instruction_src(IrInstSrc *inst) { return heap::c_allocator.destroy(reinterpret_cast(inst)); case IrInstSrcIdCallExtra: return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdAsyncCallExtra: + return heap::c_allocator.destroy(reinterpret_cast(inst)); case IrInstSrcIdUnOp: return heap::c_allocator.destroy(reinterpret_cast(inst)); case IrInstSrcIdCondBr: @@ -1173,6 +1175,10 @@ static constexpr IrInstSrcId ir_inst_id(IrInstSrcCallExtra *) { return IrInstSrcIdCallExtra; } +static constexpr IrInstSrcId ir_inst_id(IrInstSrcAsyncCallExtra *) { + return IrInstSrcIdAsyncCallExtra; +} + static constexpr IrInstSrcId ir_inst_id(IrInstSrcConst *) { return IrInstSrcIdConst; } @@ -2442,6 +2448,25 @@ static IrInstSrc *ir_build_call_extra(IrBuilderSrc *irb, Scope *scope, AstNode * return &call_instruction->base; } +static IrInstSrc *ir_build_async_call_extra(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + CallModifier modifier, IrInstSrc *fn_ref, IrInstSrc *ret_ptr, IrInstSrc *new_stack, IrInstSrc *args, ResultLoc *result_loc) +{ + IrInstSrcAsyncCallExtra *call_instruction = ir_build_instruction(irb, scope, source_node); + call_instruction->modifier = modifier; + call_instruction->fn_ref = fn_ref; + call_instruction->ret_ptr = ret_ptr; + call_instruction->new_stack = new_stack; + call_instruction->args = args; + call_instruction->result_loc = result_loc; + + ir_ref_instruction(fn_ref, irb->current_basic_block); + if (ret_ptr != nullptr) ir_ref_instruction(ret_ptr, irb->current_basic_block); + ir_ref_instruction(new_stack, irb->current_basic_block); + ir_ref_instruction(args, irb->current_basic_block); + + return &call_instruction->base; +} + static IrInstSrc *ir_build_call_args(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *options, IrInstSrc *fn_ref, IrInstSrc **args_ptr, size_t args_len, ResultLoc *result_loc) @@ -6183,11 +6208,10 @@ static IrInstSrc *ir_gen_this(IrBuilderSrc *irb, Scope *orig_scope, AstNode *nod static IrInstSrc *ir_gen_async_call(IrBuilderSrc *irb, Scope *scope, AstNode *await_node, AstNode *call_node, LVal lval, ResultLoc *result_loc) { - size_t arg_offset = 3; - if (call_node->data.fn_call_expr.params.length < arg_offset) { + if (call_node->data.fn_call_expr.params.length != 4) { add_node_error(irb->codegen, call_node, - buf_sprintf("expected at least %" ZIG_PRI_usize " arguments, found %" ZIG_PRI_usize, - arg_offset, call_node->data.fn_call_expr.params.length)); + buf_sprintf("expected 4 arguments, found %" ZIG_PRI_usize, + call_node->data.fn_call_expr.params.length)); return irb->codegen->invalid_inst_src; } @@ -6206,20 +6230,37 @@ static IrInstSrc *ir_gen_async_call(IrBuilderSrc *irb, Scope *scope, AstNode *aw if (fn_ref == irb->codegen->invalid_inst_src) return fn_ref; - size_t arg_count = call_node->data.fn_call_expr.params.length - arg_offset; - IrInstSrc **args = heap::c_allocator.allocate(arg_count); - for (size_t i = 0; i < arg_count; i += 1) { - AstNode *arg_node = call_node->data.fn_call_expr.params.at(i + arg_offset); - IrInstSrc *arg = ir_gen_node(irb, arg_node, scope); - if (arg == irb->codegen->invalid_inst_src) - return arg; - args[i] = arg; - } - CallModifier modifier = (await_node == nullptr) ? CallModifierAsync : CallModifierNone; bool is_async_call_builtin = true; - IrInstSrc *call = ir_build_call_src(irb, scope, call_node, nullptr, fn_ref, arg_count, args, - ret_ptr, modifier, is_async_call_builtin, bytes, result_loc); + AstNode *args_node = call_node->data.fn_call_expr.params.at(3); + if (args_node->type == NodeTypeContainerInitExpr) { + if (args_node->data.container_init_expr.kind == ContainerInitKindArray || + args_node->data.container_init_expr.entries.length == 0) + { + size_t arg_count = args_node->data.container_init_expr.entries.length; + IrInstSrc **args = heap::c_allocator.allocate(arg_count); + for (size_t i = 0; i < arg_count; i += 1) { + AstNode *arg_node = args_node->data.container_init_expr.entries.at(i); + IrInstSrc *arg = ir_gen_node(irb, arg_node, scope); + if (arg == irb->codegen->invalid_inst_src) + return arg; + args[i] = arg; + } + + IrInstSrc *call = ir_build_call_src(irb, scope, call_node, nullptr, fn_ref, arg_count, args, + ret_ptr, modifier, is_async_call_builtin, bytes, result_loc); + return ir_lval_wrap(irb, scope, call, lval, result_loc); + } else { + exec_add_error_node(irb->codegen, irb->exec, args_node, + buf_sprintf("TODO: @asyncCall with anon struct literal")); + return irb->codegen->invalid_inst_src; + } + } + IrInstSrc *args = ir_gen_node(irb, args_node, scope); + if (args == irb->codegen->invalid_inst_src) + return args; + + IrInstSrc *call = ir_build_async_call_extra(irb, scope, call_node, modifier, fn_ref, bytes, ret_ptr, args, result_loc); return ir_lval_wrap(irb, scope, call, lval, result_loc); } @@ -20236,7 +20277,7 @@ static IrInstGen *ir_analyze_fn_call(IrAnalyze *ira, IrInst* source_instr, // Fork a scope of the function with known values for the parameters. Scope *parent_scope = fn_entry->fndef_scope->base.parent; ZigFn *impl_fn = create_fn(ira->codegen, fn_proto_node); - impl_fn->param_source_nodes = heap::c_allocator.allocate(new_fn_arg_count); + buf_init_from_buf(&impl_fn->symbol_name, &fn_entry->symbol_name); impl_fn->fndef_scope = create_fndef_scope(ira->codegen, impl_fn->body_node, parent_scope, impl_fn); impl_fn->child_scope = &impl_fn->fndef_scope->base; @@ -20719,40 +20760,101 @@ static IrInstGen *ir_analyze_call_extra(IrAnalyze *ira, IrInst* source_instr, modifier, stack, stack_src, false, args_ptr, args_len, nullptr, result_loc); } -static IrInstGen *ir_analyze_instruction_call_extra(IrAnalyze *ira, IrInstSrcCallExtra *instruction) { - IrInstGen *args = instruction->args->child; +static IrInstGen *ir_analyze_async_call_extra(IrAnalyze *ira, IrInst* source_instr, CallModifier modifier, + IrInstSrc *pass1_fn_ref, IrInstSrc *ret_ptr, IrInstSrc *new_stack, IrInstGen **args_ptr, size_t args_len, ResultLoc *result_loc) +{ + IrInstGen *fn_ref = pass1_fn_ref->child; + if (type_is_invalid(fn_ref->value->type)) + return ira->codegen->invalid_inst_gen; + + if (ir_should_inline(ira->old_irb.exec, source_instr->scope)) { + ir_add_error(ira, source_instr, buf_sprintf("TODO: comptime @asyncCall")); + return ira->codegen->invalid_inst_gen; + } + + ZigFn *fn = nullptr; + if (instr_is_comptime(fn_ref)) { + if (fn_ref->value->type->id == ZigTypeIdBoundFn) { + assert(fn_ref->value->special == ConstValSpecialStatic); + fn = fn_ref->value->data.x_bound_fn.fn; + } else { + fn = ir_resolve_fn(ira, fn_ref); + } + } + + IrInstGen *ret_ptr_uncasted = nullptr; + if (ret_ptr != nullptr) { + ret_ptr_uncasted = ret_ptr->child; + if (type_is_invalid(ret_ptr_uncasted->value->type)) + return ira->codegen->invalid_inst_gen; + } + + ZigType *fn_type = (fn != nullptr) ? fn->type_entry : fn_ref->value->type; + IrInstGen *casted_new_stack = analyze_casted_new_stack(ira, source_instr, new_stack->child, + &new_stack->base, true, fn); + if (casted_new_stack != nullptr && type_is_invalid(casted_new_stack->value->type)) + return ira->codegen->invalid_inst_gen; + + IrInstGen *result = ir_analyze_async_call(ira, source_instr, fn, fn_type, fn_ref, args_ptr, args_len, + casted_new_stack, true, ret_ptr_uncasted, result_loc); + return ir_finish_anal(ira, result); +} + +static bool ir_extract_tuple_call_args(IrAnalyze *ira, IrInst *source_instr, IrInstGen *args, IrInstGen ***args_ptr, size_t *args_len) { ZigType *args_type = args->value->type; if (type_is_invalid(args_type)) - return ira->codegen->invalid_inst_gen; + return false; if (args_type->id != ZigTypeIdStruct) { ir_add_error(ira, &args->base, buf_sprintf("expected tuple or struct, found '%s'", buf_ptr(&args_type->name))); - return ira->codegen->invalid_inst_gen; + return false; } - IrInstGen **args_ptr = nullptr; - size_t args_len = 0; - if (is_tuple(args_type)) { - args_len = args_type->data.structure.src_field_count; - args_ptr = heap::c_allocator.allocate(args_len); - for (size_t i = 0; i < args_len; i += 1) { + *args_len = args_type->data.structure.src_field_count; + *args_ptr = heap::c_allocator.allocate(*args_len); + for (size_t i = 0; i < *args_len; i += 1) { TypeStructField *arg_field = args_type->data.structure.fields[i]; - args_ptr[i] = ir_analyze_struct_value_field_value(ira, &instruction->base.base, args, arg_field); - if (type_is_invalid(args_ptr[i]->value->type)) - return ira->codegen->invalid_inst_gen; + (*args_ptr)[i] = ir_analyze_struct_value_field_value(ira, source_instr, args, arg_field); + if (type_is_invalid((*args_ptr)[i]->value->type)) + return false; } } else { ir_add_error(ira, &args->base, buf_sprintf("TODO: struct args")); + return false; + } + return true; +} + +static IrInstGen *ir_analyze_instruction_call_extra(IrAnalyze *ira, IrInstSrcCallExtra *instruction) { + IrInstGen *args = instruction->args->child; + IrInstGen **args_ptr = nullptr; + size_t args_len = 0; + if (!ir_extract_tuple_call_args(ira, &instruction->base.base, args, &args_ptr, &args_len)) { return ira->codegen->invalid_inst_gen; } + IrInstGen *result = ir_analyze_call_extra(ira, &instruction->base.base, instruction->options, instruction->fn_ref, args_ptr, args_len, instruction->result_loc); heap::c_allocator.deallocate(args_ptr, args_len); return result; } +static IrInstGen *ir_analyze_instruction_async_call_extra(IrAnalyze *ira, IrInstSrcAsyncCallExtra *instruction) { + IrInstGen *args = instruction->args->child; + IrInstGen **args_ptr = nullptr; + size_t args_len = 0; + if (!ir_extract_tuple_call_args(ira, &instruction->base.base, args, &args_ptr, &args_len)) { + return ira->codegen->invalid_inst_gen; + } + + IrInstGen *result = ir_analyze_async_call_extra(ira, &instruction->base.base, instruction->modifier, + instruction->fn_ref, instruction->ret_ptr, instruction->new_stack, args_ptr, args_len, instruction->result_loc); + heap::c_allocator.deallocate(args_ptr, args_len); + return result; +} + static IrInstGen *ir_analyze_instruction_call_args(IrAnalyze *ira, IrInstSrcCallArgs *instruction) { IrInstGen **args_ptr = heap::c_allocator.allocate(instruction->args_len); for (size_t i = 0; i < instruction->args_len; i += 1) { @@ -31101,6 +31203,8 @@ static IrInstGen *ir_analyze_instruction_base(IrAnalyze *ira, IrInstSrc *instruc return ir_analyze_instruction_call_args(ira, (IrInstSrcCallArgs *)instruction); case IrInstSrcIdCallExtra: return ir_analyze_instruction_call_extra(ira, (IrInstSrcCallExtra *)instruction); + case IrInstSrcIdAsyncCallExtra: + return ir_analyze_instruction_async_call_extra(ira, (IrInstSrcAsyncCallExtra *)instruction); case IrInstSrcIdBr: return ir_analyze_instruction_br(ira, (IrInstSrcBr *)instruction); case IrInstSrcIdCondBr: @@ -31610,6 +31714,7 @@ bool ir_inst_src_has_side_effects(IrInstSrc *instruction) { case IrInstSrcIdDeclVar: case IrInstSrcIdStorePtr: case IrInstSrcIdCallExtra: + case IrInstSrcIdAsyncCallExtra: case IrInstSrcIdCall: case IrInstSrcIdCallArgs: case IrInstSrcIdReturn: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 27bedff47f..0acde512f6 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -5,6 +5,7 @@ * See http://opensource.org/licenses/MIT */ +#include "all_types.hpp" #include "analyze.hpp" #include "ir.hpp" #include "ir_print.hpp" @@ -55,6 +56,36 @@ struct IrPrintGen { static void ir_print_other_inst_src(IrPrintSrc *irp, IrInstSrc *inst); static void ir_print_other_inst_gen(IrPrintGen *irp, IrInstGen *inst); +static void ir_print_call_modifier(FILE *f, CallModifier modifier) { + switch (modifier) { + case CallModifierNone: + break; + case CallModifierNoSuspend: + fprintf(f, "nosuspend "); + break; + case CallModifierAsync: + fprintf(f, "async "); + break; + case CallModifierNeverTail: + fprintf(f, "notail "); + break; + case CallModifierNeverInline: + fprintf(f, "noinline "); + break; + case CallModifierAlwaysTail: + fprintf(f, "tail "); + break; + case CallModifierAlwaysInline: + fprintf(f, "inline "); + break; + case CallModifierCompileTime: + fprintf(f, "comptime "); + break; + case CallModifierBuiltin: + zig_unreachable(); + } +} + const char* ir_inst_src_type_str(IrInstSrcId id) { switch (id) { case IrInstSrcIdInvalid: @@ -97,6 +128,8 @@ const char* ir_inst_src_type_str(IrInstSrcId id) { return "SrcVarPtr"; case IrInstSrcIdCallExtra: return "SrcCallExtra"; + case IrInstSrcIdAsyncCallExtra: + return "SrcAsyncCallExtra"; case IrInstSrcIdCall: return "SrcCall"; case IrInstSrcIdCallArgs: @@ -851,6 +884,23 @@ static void ir_print_call_extra(IrPrintSrc *irp, IrInstSrcCallExtra *instruction ir_print_result_loc(irp, instruction->result_loc); } +static void ir_print_async_call_extra(IrPrintSrc *irp, IrInstSrcAsyncCallExtra *instruction) { + fprintf(irp->f, "modifier="); + ir_print_call_modifier(irp->f, instruction->modifier); + fprintf(irp->f, ", fn="); + ir_print_other_inst_src(irp, instruction->fn_ref); + if (instruction->ret_ptr != nullptr) { + fprintf(irp->f, ", ret_ptr="); + ir_print_other_inst_src(irp, instruction->ret_ptr); + } + fprintf(irp->f, ", new_stack="); + ir_print_other_inst_src(irp, instruction->new_stack); + fprintf(irp->f, ", args="); + ir_print_other_inst_src(irp, instruction->args); + fprintf(irp->f, ", result="); + ir_print_result_loc(irp, instruction->result_loc); +} + static void ir_print_call_args(IrPrintSrc *irp, IrInstSrcCallArgs *instruction) { fprintf(irp->f, "opts="); ir_print_other_inst_src(irp, instruction->options); @@ -868,33 +918,7 @@ static void ir_print_call_args(IrPrintSrc *irp, IrInstSrcCallArgs *instruction) } static void ir_print_call_src(IrPrintSrc *irp, IrInstSrcCall *call_instruction) { - switch (call_instruction->modifier) { - case CallModifierNone: - break; - case CallModifierNoSuspend: - fprintf(irp->f, "nosuspend "); - break; - case CallModifierAsync: - fprintf(irp->f, "async "); - break; - case CallModifierNeverTail: - fprintf(irp->f, "notail "); - break; - case CallModifierNeverInline: - fprintf(irp->f, "noinline "); - break; - case CallModifierAlwaysTail: - fprintf(irp->f, "tail "); - break; - case CallModifierAlwaysInline: - fprintf(irp->f, "inline "); - break; - case CallModifierCompileTime: - fprintf(irp->f, "comptime "); - break; - case CallModifierBuiltin: - zig_unreachable(); - } + ir_print_call_modifier(irp->f, call_instruction->modifier); if (call_instruction->fn_entry) { fprintf(irp->f, "%s", buf_ptr(&call_instruction->fn_entry->symbol_name)); } else { @@ -913,33 +937,7 @@ static void ir_print_call_src(IrPrintSrc *irp, IrInstSrcCall *call_instruction) } static void ir_print_call_gen(IrPrintGen *irp, IrInstGenCall *call_instruction) { - switch (call_instruction->modifier) { - case CallModifierNone: - break; - case CallModifierNoSuspend: - fprintf(irp->f, "nosuspend "); - break; - case CallModifierAsync: - fprintf(irp->f, "async "); - break; - case CallModifierNeverTail: - fprintf(irp->f, "notail "); - break; - case CallModifierNeverInline: - fprintf(irp->f, "noinline "); - break; - case CallModifierAlwaysTail: - fprintf(irp->f, "tail "); - break; - case CallModifierAlwaysInline: - fprintf(irp->f, "inline "); - break; - case CallModifierCompileTime: - fprintf(irp->f, "comptime "); - break; - case CallModifierBuiltin: - zig_unreachable(); - } + ir_print_call_modifier(irp->f, call_instruction->modifier); if (call_instruction->fn_entry) { fprintf(irp->f, "%s", buf_ptr(&call_instruction->fn_entry->symbol_name)); } else { @@ -2619,6 +2617,9 @@ static void ir_print_inst_src(IrPrintSrc *irp, IrInstSrc *instruction, bool trai case IrInstSrcIdCallExtra: ir_print_call_extra(irp, (IrInstSrcCallExtra *)instruction); break; + case IrInstSrcIdAsyncCallExtra: + ir_print_async_call_extra(irp, (IrInstSrcAsyncCallExtra *)instruction); + break; case IrInstSrcIdCall: ir_print_call_src(irp, (IrInstSrcCall *)instruction); break; -- cgit v1.2.3 From eefcd044628ea080d8fe3346ae4d01e8ed4008e6 Mon Sep 17 00:00:00 2001 From: Alexandros Naskos Date: Wed, 24 Jun 2020 16:56:24 +0300 Subject: Small fixes, fixed tests, added test for argument tuple type --- src/ir.cpp | 15 ++++++++++----- test/compile_errors.zig | 19 ++++++++++++++++--- test/stage1/behavior/async_fn.zig | 26 +++++++++++++------------- 3 files changed, 39 insertions(+), 21 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index b765ea09ff..5f44e5306b 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -6260,7 +6260,7 @@ static IrInstSrc *ir_gen_async_call(IrBuilderSrc *irb, Scope *scope, AstNode *aw if (args == irb->codegen->invalid_inst_src) return args; - IrInstSrc *call = ir_build_async_call_extra(irb, scope, call_node, modifier, fn_ref, bytes, ret_ptr, args, result_loc); + IrInstSrc *call = ir_build_async_call_extra(irb, scope, call_node, modifier, fn_ref, ret_ptr, bytes, args, result_loc); return ir_lval_wrap(irb, scope, call, lval, result_loc); } @@ -20277,7 +20277,7 @@ static IrInstGen *ir_analyze_fn_call(IrAnalyze *ira, IrInst* source_instr, // Fork a scope of the function with known values for the parameters. Scope *parent_scope = fn_entry->fndef_scope->base.parent; ZigFn *impl_fn = create_fn(ira->codegen, fn_proto_node); - + impl_fn->param_source_nodes = heap::c_allocator.allocate(new_fn_arg_count); buf_init_from_buf(&impl_fn->symbol_name, &fn_entry->symbol_name); impl_fn->fndef_scope = create_fndef_scope(ira->codegen, impl_fn->body_node, parent_scope, impl_fn); impl_fn->child_scope = &impl_fn->fndef_scope->base; @@ -20772,11 +20772,17 @@ static IrInstGen *ir_analyze_async_call_extra(IrAnalyze *ira, IrInst* source_ins return ira->codegen->invalid_inst_gen; } + IrInstGen *first_arg_ptr = nullptr; + IrInst *first_arg_ptr_src = nullptr; ZigFn *fn = nullptr; if (instr_is_comptime(fn_ref)) { if (fn_ref->value->type->id == ZigTypeIdBoundFn) { assert(fn_ref->value->special == ConstValSpecialStatic); fn = fn_ref->value->data.x_bound_fn.fn; + first_arg_ptr = fn_ref->value->data.x_bound_fn.first_arg; + first_arg_ptr_src = fn_ref->value->data.x_bound_fn.first_arg_src; + if (type_is_invalid(first_arg_ptr->value->type)) + return ira->codegen->invalid_inst_gen; } else { fn = ir_resolve_fn(ira, fn_ref); } @@ -20795,9 +20801,8 @@ static IrInstGen *ir_analyze_async_call_extra(IrAnalyze *ira, IrInst* source_ins if (casted_new_stack != nullptr && type_is_invalid(casted_new_stack->value->type)) return ira->codegen->invalid_inst_gen; - IrInstGen *result = ir_analyze_async_call(ira, source_instr, fn, fn_type, fn_ref, args_ptr, args_len, - casted_new_stack, true, ret_ptr_uncasted, result_loc); - return ir_finish_anal(ira, result); + return ir_analyze_fn_call(ira, source_instr, fn, fn_type, fn_ref, first_arg_ptr, first_arg_ptr_src, + modifier, casted_new_stack, &new_stack->base, true, args_ptr, args_len, ret_ptr_uncasted, result_loc); } static bool ir_extract_tuple_call_args(IrAnalyze *ira, IrInst *source_instr, IrInstGen *args, IrInstGen ***args_ptr, size_t *args_len) { diff --git a/test/compile_errors.zig b/test/compile_errors.zig index e8b7e610ee..90c970c842 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1144,13 +1144,26 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:2:15: error: @Type not available for 'TypeInfo.Struct'", }); + cases.add("wrong type for argument tuple to @asyncCall", + \\export fn entry1() void { + \\ var frame: @Frame(foo) = undefined; + \\ @asyncCall(&frame, {}, foo, {}); + \\} + \\ + \\fn foo() i32 { + \\ return 0; + \\} + , &[_][]const u8{ + "tmp.zig:3:33: error: expected tuple or struct, found 'void'", + }); + cases.add("wrong type for result ptr to @asyncCall", \\export fn entry() void { \\ _ = async amain(); \\} \\fn amain() i32 { \\ var frame: @Frame(foo) = undefined; - \\ return await @asyncCall(&frame, false, foo); + \\ return await @asyncCall(&frame, false, foo, .{}); \\} \\fn foo() i32 { \\ return 1234; @@ -1291,7 +1304,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\export fn entry() void { \\ var ptr: fn () callconv(.Async) void = func; \\ var bytes: [64]u8 = undefined; - \\ _ = @asyncCall(&bytes, {}, ptr); + \\ _ = @asyncCall(&bytes, {}, ptr, .{}); \\} \\fn func() callconv(.Async) void {} , &[_][]const u8{ @@ -1467,7 +1480,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\export fn entry() void { \\ var ptr = afunc; \\ var bytes: [100]u8 align(16) = undefined; - \\ _ = @asyncCall(&bytes, {}, ptr); + \\ _ = @asyncCall(&bytes, {}, ptr, .{}); \\} \\fn afunc() void { } , &[_][]const u8{ diff --git a/test/stage1/behavior/async_fn.zig b/test/stage1/behavior/async_fn.zig index 30df7f64aa..4214ed84d2 100644 --- a/test/stage1/behavior/async_fn.zig +++ b/test/stage1/behavior/async_fn.zig @@ -282,7 +282,7 @@ test "async fn pointer in a struct field" { }; var foo = Foo{ .bar = simpleAsyncFn2 }; var bytes: [64]u8 align(16) = undefined; - const f = @asyncCall(&bytes, {}, foo.bar, &data); + const f = @asyncCall(&bytes, {}, foo.bar, .{&data}); comptime expect(@TypeOf(f) == anyframe->void); expect(data == 2); resume f; @@ -318,7 +318,7 @@ test "@asyncCall with return type" { var foo = Foo{ .bar = Foo.middle }; var bytes: [150]u8 align(16) = undefined; var aresult: i32 = 0; - _ = @asyncCall(&bytes, &aresult, foo.bar); + _ = @asyncCall(&bytes, &aresult, foo.bar, .{}); expect(aresult == 0); resume Foo.global_frame; expect(aresult == 1234); @@ -332,7 +332,7 @@ test "async fn with inferred error set" { var frame: [1]@Frame(middle) = undefined; var fn_ptr = middle; var result: @TypeOf(fn_ptr).ReturnType.ErrorSet!void = undefined; - _ = @asyncCall(std.mem.sliceAsBytes(frame[0..]), &result, fn_ptr); + _ = @asyncCall(std.mem.sliceAsBytes(frame[0..]), &result, fn_ptr, .{}); resume global_frame; std.testing.expectError(error.Fail, result); } @@ -827,7 +827,7 @@ test "cast fn to async fn when it is inferred to be async" { ptr = func; var buf: [100]u8 align(16) = undefined; var result: i32 = undefined; - const f = @asyncCall(&buf, &result, ptr); + const f = @asyncCall(&buf, &result, ptr, .{}); _ = await f; expect(result == 1234); ok = true; @@ -855,7 +855,7 @@ test "cast fn to async fn when it is inferred to be async, awaited directly" { ptr = func; var buf: [100]u8 align(16) = undefined; var result: i32 = undefined; - _ = await @asyncCall(&buf, &result, ptr); + _ = await @asyncCall(&buf, &result, ptr, .{}); expect(result == 1234); ok = true; } @@ -951,7 +951,7 @@ test "@asyncCall with comptime-known function, but not awaited directly" { fn doTheTest() void { var frame: [1]@Frame(middle) = undefined; var result: @TypeOf(middle).ReturnType.ErrorSet!void = undefined; - _ = @asyncCall(std.mem.sliceAsBytes(frame[0..]), &result, middle); + _ = @asyncCall(std.mem.sliceAsBytes(frame[0..]), &result, middle, .{}); resume global_frame; std.testing.expectError(error.Fail, result); } @@ -982,7 +982,7 @@ test "@asyncCall with actual frame instead of byte buffer" { }; var frame: @Frame(S.func) = undefined; var result: i32 = undefined; - const ptr = @asyncCall(&frame, &result, S.func); + const ptr = @asyncCall(&frame, &result, S.func, .{}); resume ptr; expect(result == 1234); } @@ -1005,7 +1005,7 @@ test "@asyncCall using the result location inside the frame" { }; var foo = Foo{ .bar = S.simple2 }; var bytes: [64]u8 align(16) = undefined; - const f = @asyncCall(&bytes, {}, foo.bar, &data); + const f = @asyncCall(&bytes, {}, foo.bar, .{&data}); comptime expect(@TypeOf(f) == anyframe->i32); expect(data == 2); resume f; @@ -1042,7 +1042,7 @@ test "using @TypeOf on a generic function call" { } const F = @TypeOf(async amain(x - 1)); const frame = @intToPtr(*F, @ptrToInt(&buf)); - return await @asyncCall(frame, {}, amain, x - 1); + return await @asyncCall(frame, {}, amain, .{x - 1}); } }; _ = async S.amain(@as(u32, 1)); @@ -1067,7 +1067,7 @@ test "recursive call of await @asyncCall with struct return type" { } const F = @TypeOf(async amain(x - 1)); const frame = @intToPtr(*F, @ptrToInt(&buf)); - return await @asyncCall(frame, {}, amain, x - 1); + return await @asyncCall(frame, {}, amain, .{x - 1}); } const Foo = struct { @@ -1078,7 +1078,7 @@ test "recursive call of await @asyncCall with struct return type" { }; var res: S.Foo = undefined; var frame: @TypeOf(async S.amain(@as(u32, 1))) = undefined; - _ = @asyncCall(&frame, &res, S.amain, @as(u32, 1)); + _ = @asyncCall(&frame, &res, S.amain, .{@as(u32, 1)}); resume S.global_frame; expect(S.global_ok); expect(res.x == 1); @@ -1377,7 +1377,7 @@ test "async function call resolves target fn frame, comptime func" { fn foo() anyerror!void { const stack_size = 1000; var stack_frame: [stack_size]u8 align(std.Target.stack_align) = undefined; - return await @asyncCall(&stack_frame, {}, bar); + return await @asyncCall(&stack_frame, {}, bar, .{}); } fn bar() anyerror!void { @@ -1400,7 +1400,7 @@ test "async function call resolves target fn frame, runtime func" { const stack_size = 1000; var stack_frame: [stack_size]u8 align(std.Target.stack_align) = undefined; var func: fn () callconv(.Async) anyerror!void = bar; - return await @asyncCall(&stack_frame, {}, func); + return await @asyncCall(&stack_frame, {}, func, .{}); } fn bar() anyerror!void { -- cgit v1.2.3 From 2fde8249b72f22ddfa16793c245315f30c7f3ff8 Mon Sep 17 00:00:00 2001 From: Alexandros Naskos Date: Wed, 24 Jun 2020 21:04:31 +0300 Subject: Fixed crash when resolving peer types of *[N:s]const T and [*:s]const T --- src/ir.cpp | 1 + test/stage1/behavior.zig | 1 + test/stage1/behavior/bugs/5413.zig | 6 ++++++ 3 files changed, 8 insertions(+) create mode 100644 test/stage1/behavior/bugs/5413.zig (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 01c7936f75..3e2b75822e 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -12603,6 +12603,7 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT prev_type->data.pointer.child_type->id == ZigTypeIdArray && ((cur_type->id == ZigTypeIdPointer && cur_type->data.pointer.ptr_len == PtrLenUnknown))) { + convert_to_const_slice = false; prev_inst = cur_inst; if (prev_type->data.pointer.is_const && !cur_type->data.pointer.is_const) { diff --git a/test/stage1/behavior.zig b/test/stage1/behavior.zig index 8c567fa99f..a15f1f26b9 100644 --- a/test/stage1/behavior.zig +++ b/test/stage1/behavior.zig @@ -50,6 +50,7 @@ comptime { _ = @import("behavior/bugs/4769_b.zig"); _ = @import("behavior/bugs/4769_c.zig"); _ = @import("behavior/bugs/4954.zig"); + _ = @import("behavior/bugs/5413.zig"); _ = @import("behavior/bugs/5474.zig"); _ = @import("behavior/bugs/5487.zig"); _ = @import("behavior/bugs/394.zig"); diff --git a/test/stage1/behavior/bugs/5413.zig b/test/stage1/behavior/bugs/5413.zig new file mode 100644 index 0000000000..5ef533a761 --- /dev/null +++ b/test/stage1/behavior/bugs/5413.zig @@ -0,0 +1,6 @@ +const expect = @import("std").testing.expect; + +test "Peer type resolution with string literals and unknown length u8 pointers" { + expect(@TypeOf("", "a", @as([*:0]const u8, "")) == [*:0]const u8); + expect(@TypeOf(@as([*:0]const u8, "baz"), "foo", "bar") == [*:0]const u8); +} -- cgit v1.2.3 From 78d8931647f207965ef98354db67fb880987fafe Mon Sep 17 00:00:00 2001 From: arbrk1 Date: Thu, 25 Jun 2020 06:58:50 +0300 Subject: Fix issue #5618 (#5685) * fix issue #5618 * A test for the issue #5618 added. Also inserted a comma in the neighboring test to make it more zigfmt-friendly. --- src/ir.cpp | 1 + test/compile_errors.zig | 12 +++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 3e2b75822e..20067b74d1 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -15452,6 +15452,7 @@ static IrInstGen *ir_analyze_cast(IrAnalyze *ira, IrInst *source_instr, if (is_pointery_and_elem_is_not_pointery(actual_type)) { ZigType *dest_ptr_type = nullptr; if (wanted_type->id == ZigTypeIdPointer && + actual_type->id != ZigTypeIdOptional && wanted_type->data.pointer.child_type == ira->codegen->builtin_types.entry_c_void) { dest_ptr_type = wanted_type; diff --git a/test/compile_errors.zig b/test/compile_errors.zig index e8b7e610ee..79ecaee7c1 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -7571,6 +7571,16 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return -y; \\} , &[_][]const u8{ - "tmp.zig:3:12: error: negation of type 'u32'" + "tmp.zig:3:12: error: negation of type 'u32'", + }); + + cases.add("Issue #5618: coercion of ?*c_void to *c_void must fail.", + \\export fn foo() void { + \\ var u: ?*c_void = null; + \\ var v: *c_void = undefined; + \\ v = u; + \\} + , &[_][]const u8{ + "tmp.zig:4:9: error: expected type '*c_void', found '?*c_void'", }); } -- cgit v1.2.3 From 2e1bdd0d14f490a80bbed3ee0e0479a908715d33 Mon Sep 17 00:00:00 2001 From: Vexu Date: Thu, 9 Jul 2020 21:25:55 +0300 Subject: use correct cast function when doing `@floatCast` at comptime Closes #5832 --- src/ir.cpp | 2 +- test/stage1/behavior/cast.zig | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index a45455ad39..81b7f14f84 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -26718,7 +26718,7 @@ static IrInstGen *ir_analyze_instruction_float_cast(IrAnalyze *ira, IrInstSrcFlo } if (instr_is_comptime(target) || dest_type->id == ZigTypeIdComptimeFloat) { - return ir_implicit_cast2(ira, &instruction->target->base, target, dest_type); + return ir_analyze_widen_or_shorten(ira, &instruction->target->base, target, dest_type); } if (target->value->type->id != ZigTypeIdFloat) { diff --git a/test/stage1/behavior/cast.zig b/test/stage1/behavior/cast.zig index 77cdacc307..4325b0b9e4 100644 --- a/test/stage1/behavior/cast.zig +++ b/test/stage1/behavior/cast.zig @@ -384,6 +384,19 @@ test "@intCast i32 to u7" { expect(z == 0xff); } +test "@floatCast cast down" { + { + var double: f64 = 0.001534; + var single = @floatCast(f32, double); + expect(@TypeOf(single) == f32); + } + { + const double: f64 = 0.001534; + const single = @floatCast(f32, double); + expect(@TypeOf(single) == f32); + } +} + test "implicit cast undefined to optional" { expect(MakeType(void).getNull() == null); expect(MakeType(void).getNonNull() != null); -- cgit v1.2.3 From 02619edf413cd3b8b01a6a3514ecd257d7c08b6e Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 9 Jul 2020 23:24:21 -0700 Subject: Revert "use correct cast function when doing `@floatCast` at comptime" This reverts commit 2e1bdd0d14f490a80bbed3ee0e0479a908715d33. Test failures --- src/ir.cpp | 2 +- test/stage1/behavior/cast.zig | 13 ------------- 2 files changed, 1 insertion(+), 14 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 81b7f14f84..a45455ad39 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -26718,7 +26718,7 @@ static IrInstGen *ir_analyze_instruction_float_cast(IrAnalyze *ira, IrInstSrcFlo } if (instr_is_comptime(target) || dest_type->id == ZigTypeIdComptimeFloat) { - return ir_analyze_widen_or_shorten(ira, &instruction->target->base, target, dest_type); + return ir_implicit_cast2(ira, &instruction->target->base, target, dest_type); } if (target->value->type->id != ZigTypeIdFloat) { diff --git a/test/stage1/behavior/cast.zig b/test/stage1/behavior/cast.zig index 4325b0b9e4..77cdacc307 100644 --- a/test/stage1/behavior/cast.zig +++ b/test/stage1/behavior/cast.zig @@ -384,19 +384,6 @@ test "@intCast i32 to u7" { expect(z == 0xff); } -test "@floatCast cast down" { - { - var double: f64 = 0.001534; - var single = @floatCast(f32, double); - expect(@TypeOf(single) == f32); - } - { - const double: f64 = 0.001534; - const single = @floatCast(f32, double); - expect(@TypeOf(single) == f32); - } -} - test "implicit cast undefined to optional" { expect(MakeType(void).getNull() == null); expect(MakeType(void).getNonNull() != null); -- cgit v1.2.3 From 2e037fd827487ce94ae0beb313a1f0536085d61e Mon Sep 17 00:00:00 2001 From: Vexu Date: Fri, 10 Jul 2020 17:30:50 +0300 Subject: use correct cast function when doing `@floatCast` at comptime --- src/ir.cpp | 20 +++++++++++++------- test/compile_errors.zig | 32 ++++++++++++++++++-------------- test/stage1/behavior/cast.zig | 13 +++++++++++++ 3 files changed, 44 insertions(+), 21 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index a45455ad39..ca0fd47c49 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -13020,7 +13020,11 @@ static IrInstGen *ir_resolve_cast(IrAnalyze *ira, IrInst *source_instr, IrInstGe { if (instr_is_comptime(value) || !type_has_bits(ira->codegen, wanted_type)) { IrInstGen *result = ir_const(ira, source_instr, wanted_type); - if (!eval_const_expr_implicit_cast(ira, source_instr, cast_op, value->value, value->value->type, + ZigValue *val = ir_resolve_const(ira, value, UndefBad); + if (val == nullptr) + return ira->codegen->invalid_inst_gen; + + if (!eval_const_expr_implicit_cast(ira, source_instr, cast_op, val, val->type, result->value, wanted_type)) { return ira->codegen->invalid_inst_gen; @@ -26680,6 +26684,10 @@ static IrInstGen *ir_analyze_instruction_int_cast(IrAnalyze *ira, IrInstSrcIntCa } if (instr_is_comptime(target) || dest_type->id == ZigTypeIdComptimeInt) { + ZigValue *val = ir_resolve_const(ira, target, UndefBad); + if (val == nullptr) + return ira->codegen->invalid_inst_gen; + return ir_implicit_cast2(ira, &instruction->target->base, target, dest_type); } @@ -26718,13 +26726,11 @@ static IrInstGen *ir_analyze_instruction_float_cast(IrAnalyze *ira, IrInstSrcFlo } if (instr_is_comptime(target) || dest_type->id == ZigTypeIdComptimeFloat) { - return ir_implicit_cast2(ira, &instruction->target->base, target, dest_type); - } + ZigValue *val = ir_resolve_const(ira, target, UndefBad); + if (val == nullptr) + return ira->codegen->invalid_inst_gen; - if (target->value->type->id != ZigTypeIdFloat) { - ir_add_error(ira, &instruction->target->base, buf_sprintf("expected float type, found '%s'", - buf_ptr(&target->value->type->name))); - return ira->codegen->invalid_inst_gen; + return ir_analyze_widen_or_shorten(ira, &instruction->target->base, target, dest_type); } return ir_analyze_widen_or_shorten(ira, &instruction->base.base, target, dest_type); diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 611094c050..df2e759bf1 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -2,6 +2,22 @@ const tests = @import("tests.zig"); const std = @import("std"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.addTest("int/float conversion to comptime_int/float", + \\export fn foo() void { + \\ var a: f32 = 2; + \\ _ = @floatToInt(comptime_int, a); + \\} + \\export fn bar() void { + \\ var a: u32 = 2; + \\ _ = @intToFloat(comptime_float, a); + \\} + , &[_][]const u8{ + "tmp.zig:3:35: error: unable to evaluate constant expression", + "tmp.zig:3:9: note: referenced here", + "tmp.zig:7:37: error: unable to evaluate constant expression", + "tmp.zig:7:9: note: referenced here", + }); + cases.add("extern variable has no type", \\extern var foo; \\pub export fn entry() void { @@ -90,19 +106,13 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ var a: u32 = 2; \\ _ = @floatToInt(u32, a); \\} - \\export fn qux() void { - \\ var a: u32 = 2; - \\ _ = @intCast(comptime_int, a); - \\} , &[_][]const u8{ - "tmp.zig:3:32: error: expected type 'comptime_int', found 'u32'", + "tmp.zig:3:32: error: unable to evaluate constant expression", "tmp.zig:3:9: note: referenced here", "tmp.zig:7:21: error: expected float type, found 'u32'", "tmp.zig:7:9: note: referenced here", "tmp.zig:11:26: error: expected float type, found 'u32'", "tmp.zig:11:9: note: referenced here", - "tmp.zig:15:32: error: expected type 'comptime_int', found 'u32'", - "tmp.zig:15:9: note: referenced here", }); cases.addTest("invalid float casts", @@ -118,19 +128,13 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ var a: f32 = 2; \\ _ = @intToFloat(f32, a); \\} - \\export fn qux() void { - \\ var a: f32 = 2; - \\ _ = @floatCast(comptime_float, a); - \\} , &[_][]const u8{ - "tmp.zig:3:36: error: expected type 'comptime_float', found 'f32'", + "tmp.zig:3:36: error: unable to evaluate constant expression", "tmp.zig:3:9: note: referenced here", "tmp.zig:7:21: error: expected integer type, found 'f32'", "tmp.zig:7:9: note: referenced here", "tmp.zig:11:26: error: expected int type, found 'f32'", "tmp.zig:11:9: note: referenced here", - "tmp.zig:15:36: error: expected type 'comptime_float', found 'f32'", - "tmp.zig:15:9: note: referenced here", }); cases.addTest("invalid assignments", diff --git a/test/stage1/behavior/cast.zig b/test/stage1/behavior/cast.zig index 77cdacc307..4b678cd2db 100644 --- a/test/stage1/behavior/cast.zig +++ b/test/stage1/behavior/cast.zig @@ -384,6 +384,19 @@ test "@intCast i32 to u7" { expect(z == 0xff); } +test "@floatCast cast down" { + { + var double: f64 = 0.001534; + var single = @floatCast(f32, double); + expect(single == 0.001534); + } + { + const double: f64 = 0.001534; + const single = @floatCast(f32, double); + expect(single == 0.001534); + } +} + test "implicit cast undefined to optional" { expect(MakeType(void).getNull() == null); expect(MakeType(void).getNonNull() != null); -- cgit v1.2.3 From 8110639c7964fcb23c2b715f97ab6caa27506b93 Mon Sep 17 00:00:00 2001 From: Vexu Date: Sat, 11 Jul 2020 14:08:20 +0300 Subject: add 'anytype' to stage1 and langref --- doc/langref.html.in | 87 +++++++++++++++++++++++++++-------------------------- src/all_types.hpp | 8 ++--- src/analyze.cpp | 16 +++++----- src/ast_render.cpp | 16 +++++----- src/codegen.cpp | 4 +-- src/ir.cpp | 59 +++++++++++++++++++----------------- src/parser.cpp | 26 ++++++++-------- src/tokenizer.cpp | 2 ++ src/tokenizer.hpp | 1 + 9 files changed, 114 insertions(+), 105 deletions(-) (limited to 'src/ir.cpp') diff --git a/doc/langref.html.in b/doc/langref.html.in index f64170817f..015865ee3b 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -1785,7 +1785,7 @@ test "fully anonymous list literal" { dump(.{ @as(u32, 1234), @as(f64, 12.34), true, "hi"}); } -fn dump(args: var) void { +fn dump(args: anytype) void { assert(args.@"0" == 1234); assert(args.@"1" == 12.34); assert(args.@"2"); @@ -2717,7 +2717,7 @@ test "fully anonymous struct" { }); } -fn dump(args: var) void { +fn dump(args: anytype) void { assert(args.int == 1234); assert(args.float == 12.34); assert(args.b); @@ -4181,14 +4181,14 @@ test "pass struct to function" { {#header_close#} {#header_open|Function Parameter Type Inference#}

- Function parameters can be declared with {#syntax#}var{#endsyntax#} in place of the type. + Function parameters can be declared with {#syntax#}anytype{#endsyntax#} in place of the type. In this case the parameter types will be inferred when the function is called. Use {#link|@TypeOf#} and {#link|@typeInfo#} to get information about the inferred type.

{#code_begin|test#} const assert = @import("std").debug.assert; -fn addFortyTwo(x: var) @TypeOf(x) { +fn addFortyTwo(x: anytype) @TypeOf(x) { return x + 42; } @@ -5974,7 +5974,7 @@ pub fn main() void { {#code_begin|syntax#} /// Calls print and then flushes the buffer. -pub fn printf(self: *OutStream, comptime format: []const u8, args: var) anyerror!void { +pub fn printf(self: *OutStream, comptime format: []const u8, args: anytype) anyerror!void { const State = enum { Start, OpenBrace, @@ -6060,7 +6060,7 @@ pub fn printf(self: *OutStream, arg0: i32, arg1: []const u8) !void { on the type:

{#code_begin|syntax#} -pub fn printValue(self: *OutStream, value: var) !void { +pub fn printValue(self: *OutStream, value: anytype) !void { switch (@typeInfo(@TypeOf(value))) { .Int => { return self.printInt(T, value); @@ -6686,7 +6686,7 @@ fn readFile(allocator: *Allocator, filename: []const u8) ![]u8 {

{#header_close#} {#header_open|@alignCast#} -
{#syntax#}@alignCast(comptime alignment: u29, ptr: var) var{#endsyntax#}
+
{#syntax#}@alignCast(comptime alignment: u29, ptr: anytype) anytype{#endsyntax#}

{#syntax#}ptr{#endsyntax#} can be {#syntax#}*T{#endsyntax#}, {#syntax#}fn(){#endsyntax#}, {#syntax#}?*T{#endsyntax#}, {#syntax#}?fn(){#endsyntax#}, or {#syntax#}[]T{#endsyntax#}. It returns the same type as {#syntax#}ptr{#endsyntax#} @@ -6723,7 +6723,7 @@ comptime { {#header_close#} {#header_open|@asyncCall#} -

{#syntax#}@asyncCall(frame_buffer: []align(@alignOf(@Frame(anyAsyncFunction))) u8, result_ptr, function_ptr, args: var) anyframe->T{#endsyntax#}
+
{#syntax#}@asyncCall(frame_buffer: []align(@alignOf(@Frame(anyAsyncFunction))) u8, result_ptr, function_ptr, args: anytype) anyframe->T{#endsyntax#}

{#syntax#}@asyncCall{#endsyntax#} performs an {#syntax#}async{#endsyntax#} call on a function pointer, which may or may not be an {#link|async function|Async Functions#}. @@ -6811,7 +6811,7 @@ fn func(y: *i32) void {

{#header_close#} {#header_open|@bitCast#} -
{#syntax#}@bitCast(comptime DestType: type, value: var) DestType{#endsyntax#}
+
{#syntax#}@bitCast(comptime DestType: type, value: anytype) DestType{#endsyntax#}

Converts a value of one type to another type.

@@ -6932,7 +6932,7 @@ fn func(y: *i32) void { {#header_close#} {#header_open|@call#} -
{#syntax#}@call(options: std.builtin.CallOptions, function: var, args: var) var{#endsyntax#}
+
{#syntax#}@call(options: std.builtin.CallOptions, function: anytype, args: anytype) anytype{#endsyntax#}

Calls a function, in the same way that invoking an expression with parentheses does:

@@ -7279,7 +7279,7 @@ test "main" { {#header_close#} {#header_open|@enumToInt#} -
{#syntax#}@enumToInt(enum_or_tagged_union: var) var{#endsyntax#}
+
{#syntax#}@enumToInt(enum_or_tagged_union: anytype) anytype{#endsyntax#}

Converts an enumeration value into its integer tag type. When a tagged union is passed, the tag value is used as the enumeration value. @@ -7314,7 +7314,7 @@ test "main" { {#header_close#} {#header_open|@errorToInt#} -

{#syntax#}@errorToInt(err: var) std.meta.IntType(false, @sizeOf(anyerror) * 8){#endsyntax#}
+
{#syntax#}@errorToInt(err: anytype) std.meta.IntType(false, @sizeOf(anyerror) * 8){#endsyntax#}

Supports the following types:

@@ -7334,7 +7334,7 @@ test "main" { {#header_close#} {#header_open|@errSetCast#} -
{#syntax#}@errSetCast(comptime T: DestType, value: var) DestType{#endsyntax#}
+
{#syntax#}@errSetCast(comptime T: DestType, value: anytype) DestType{#endsyntax#}

Converts an error value from one error set to another error set. Attempting to convert an error which is not in the destination error set results in safety-protected {#link|Undefined Behavior#}. @@ -7342,7 +7342,7 @@ test "main" { {#header_close#} {#header_open|@export#} -

{#syntax#}@export(target: var, comptime options: std.builtin.ExportOptions) void{#endsyntax#}
+
{#syntax#}@export(target: anytype, comptime options: std.builtin.ExportOptions) void{#endsyntax#}

Creates a symbol in the output object file.

@@ -7387,7 +7387,7 @@ export fn @"A function name that is a complete sentence."() void {} {#header_close#} {#header_open|@field#} -
{#syntax#}@field(lhs: var, comptime field_name: []const u8) (field){#endsyntax#}
+
{#syntax#}@field(lhs: anytype, comptime field_name: []const u8) (field){#endsyntax#}

Performs field access by a compile-time string.

{#code_begin|test#} @@ -7421,7 +7421,7 @@ test "field access by string" { {#header_close#} {#header_open|@floatCast#} -
{#syntax#}@floatCast(comptime DestType: type, value: var) DestType{#endsyntax#}
+
{#syntax#}@floatCast(comptime DestType: type, value: anytype) DestType{#endsyntax#}

Convert from one float type to another. This cast is safe, but may cause the numeric value to lose precision. @@ -7429,7 +7429,7 @@ test "field access by string" { {#header_close#} {#header_open|@floatToInt#} -

{#syntax#}@floatToInt(comptime DestType: type, float: var) DestType{#endsyntax#}
+
{#syntax#}@floatToInt(comptime DestType: type, float: anytype) DestType{#endsyntax#}

Converts the integer part of a floating point number to the destination type.

@@ -7455,7 +7455,7 @@ test "field access by string" { {#header_close#} {#header_open|@Frame#} -
{#syntax#}@Frame(func: var) type{#endsyntax#}
+
{#syntax#}@Frame(func: anytype) type{#endsyntax#}

This function returns the frame type of a function. This works for {#link|Async Functions#} as well as any function without a specific calling convention. @@ -7581,7 +7581,7 @@ test "@hasDecl" { {#header_close#} {#header_open|@intCast#} -

{#syntax#}@intCast(comptime DestType: type, int: var) DestType{#endsyntax#}
+
{#syntax#}@intCast(comptime DestType: type, int: anytype) DestType{#endsyntax#}

Converts an integer to another integer while keeping the same numerical value. Attempting to convert a number which is out of range of the destination type results in @@ -7622,7 +7622,7 @@ test "@hasDecl" { {#header_close#} {#header_open|@intToFloat#} -

{#syntax#}@intToFloat(comptime DestType: type, int: var) DestType{#endsyntax#}
+
{#syntax#}@intToFloat(comptime DestType: type, int: anytype) DestType{#endsyntax#}

Converts an integer to the closest floating point representation. To convert the other way, use {#link|@floatToInt#}. This cast is always safe.

@@ -7773,7 +7773,7 @@ test "@wasmMemoryGrow" { {#header_close#} {#header_open|@ptrCast#} -
{#syntax#}@ptrCast(comptime DestType: type, value: var) DestType{#endsyntax#}
+
{#syntax#}@ptrCast(comptime DestType: type, value: anytype) DestType{#endsyntax#}

Converts a pointer of one type to a pointer of another type.

@@ -7784,7 +7784,7 @@ test "@wasmMemoryGrow" { {#header_close#} {#header_open|@ptrToInt#} -
{#syntax#}@ptrToInt(value: var) usize{#endsyntax#}
+
{#syntax#}@ptrToInt(value: anytype) usize{#endsyntax#}

Converts {#syntax#}value{#endsyntax#} to a {#syntax#}usize{#endsyntax#} which is the address of the pointer. {#syntax#}value{#endsyntax#} can be one of these types:

@@ -8042,7 +8042,7 @@ test "@setRuntimeSafety" { {#header_close#} {#header_open|@splat#} -
{#syntax#}@splat(comptime len: u32, scalar: var) std.meta.Vector(len, @TypeOf(scalar)){#endsyntax#}
+
{#syntax#}@splat(comptime len: u32, scalar: anytype) std.meta.Vector(len, @TypeOf(scalar)){#endsyntax#}

Produces a vector of length {#syntax#}len{#endsyntax#} where each element is the value {#syntax#}scalar{#endsyntax#}: @@ -8088,7 +8088,7 @@ fn doTheTest() void { {#code_end#} {#header_close#} {#header_open|@sqrt#} -

{#syntax#}@sqrt(value: var) @TypeOf(value){#endsyntax#}
+
{#syntax#}@sqrt(value: anytype) @TypeOf(value){#endsyntax#}

Performs the square root of a floating point number. Uses a dedicated hardware instruction when available. @@ -8099,7 +8099,7 @@ fn doTheTest() void {

{#header_close#} {#header_open|@sin#} -
{#syntax#}@sin(value: var) @TypeOf(value){#endsyntax#}
+
{#syntax#}@sin(value: anytype) @TypeOf(value){#endsyntax#}

Sine trigometric function on a floating point number. Uses a dedicated hardware instruction when available. @@ -8110,7 +8110,7 @@ fn doTheTest() void {

{#header_close#} {#header_open|@cos#} -
{#syntax#}@cos(value: var) @TypeOf(value){#endsyntax#}
+
{#syntax#}@cos(value: anytype) @TypeOf(value){#endsyntax#}

Cosine trigometric function on a floating point number. Uses a dedicated hardware instruction when available. @@ -8121,7 +8121,7 @@ fn doTheTest() void {

{#header_close#} {#header_open|@exp#} -
{#syntax#}@exp(value: var) @TypeOf(value){#endsyntax#}
+
{#syntax#}@exp(value: anytype) @TypeOf(value){#endsyntax#}

Base-e exponential function on a floating point number. Uses a dedicated hardware instruction when available. @@ -8132,7 +8132,7 @@ fn doTheTest() void {

{#header_close#} {#header_open|@exp2#} -
{#syntax#}@exp2(value: var) @TypeOf(value){#endsyntax#}
+
{#syntax#}@exp2(value: anytype) @TypeOf(value){#endsyntax#}

Base-2 exponential function on a floating point number. Uses a dedicated hardware instruction when available. @@ -8143,7 +8143,7 @@ fn doTheTest() void {

{#header_close#} {#header_open|@log#} -
{#syntax#}@log(value: var) @TypeOf(value){#endsyntax#}
+
{#syntax#}@log(value: anytype) @TypeOf(value){#endsyntax#}

Returns the natural logarithm of a floating point number. Uses a dedicated hardware instruction when available. @@ -8154,7 +8154,7 @@ fn doTheTest() void {

{#header_close#} {#header_open|@log2#} -
{#syntax#}@log2(value: var) @TypeOf(value){#endsyntax#}
+
{#syntax#}@log2(value: anytype) @TypeOf(value){#endsyntax#}

Returns the logarithm to the base 2 of a floating point number. Uses a dedicated hardware instruction when available. @@ -8165,7 +8165,7 @@ fn doTheTest() void {

{#header_close#} {#header_open|@log10#} -
{#syntax#}@log10(value: var) @TypeOf(value){#endsyntax#}
+
{#syntax#}@log10(value: anytype) @TypeOf(value){#endsyntax#}

Returns the logarithm to the base 10 of a floating point number. Uses a dedicated hardware instruction when available. @@ -8176,7 +8176,7 @@ fn doTheTest() void {

{#header_close#} {#header_open|@fabs#} -
{#syntax#}@fabs(value: var) @TypeOf(value){#endsyntax#}
+
{#syntax#}@fabs(value: anytype) @TypeOf(value){#endsyntax#}

Returns the absolute value of a floating point number. Uses a dedicated hardware instruction when available. @@ -8187,7 +8187,7 @@ fn doTheTest() void {

{#header_close#} {#header_open|@floor#} -
{#syntax#}@floor(value: var) @TypeOf(value){#endsyntax#}
+
{#syntax#}@floor(value: anytype) @TypeOf(value){#endsyntax#}

Returns the largest integral value not greater than the given floating point number. Uses a dedicated hardware instruction when available. @@ -8198,7 +8198,7 @@ fn doTheTest() void {

{#header_close#} {#header_open|@ceil#} -
{#syntax#}@ceil(value: var) @TypeOf(value){#endsyntax#}
+
{#syntax#}@ceil(value: anytype) @TypeOf(value){#endsyntax#}

Returns the largest integral value not less than the given floating point number. Uses a dedicated hardware instruction when available. @@ -8209,7 +8209,7 @@ fn doTheTest() void {

{#header_close#} {#header_open|@trunc#} -
{#syntax#}@trunc(value: var) @TypeOf(value){#endsyntax#}
+
{#syntax#}@trunc(value: anytype) @TypeOf(value){#endsyntax#}

Rounds the given floating point number to an integer, towards zero. Uses a dedicated hardware instruction when available. @@ -8220,7 +8220,7 @@ fn doTheTest() void {

{#header_close#} {#header_open|@round#} -
{#syntax#}@round(value: var) @TypeOf(value){#endsyntax#}
+
{#syntax#}@round(value: anytype) @TypeOf(value){#endsyntax#}

Rounds the given floating point number to an integer, away from zero. Uses a dedicated hardware instruction when available. @@ -8241,7 +8241,7 @@ fn doTheTest() void { {#header_close#} {#header_open|@tagName#} -

{#syntax#}@tagName(value: var) []const u8{#endsyntax#}
+
{#syntax#}@tagName(value: anytype) []const u8{#endsyntax#}

Converts an enum value or union value to a slice of bytes representing the name.

If the enum is non-exhaustive and the tag value does not map to a name, it invokes safety-checked {#link|Undefined Behavior#}.

@@ -8292,7 +8292,7 @@ fn List(comptime T: type) type { {#header_close#} {#header_open|@truncate#} -
{#syntax#}@truncate(comptime T: type, integer: var) T{#endsyntax#}
+
{#syntax#}@truncate(comptime T: type, integer: anytype) T{#endsyntax#}

This function truncates bits from an integer type, resulting in a smaller or same-sized integer type. @@ -10214,7 +10214,7 @@ TopLevelDecl / (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? VarDecl / KEYWORD_usingnamespace Expr SEMICOLON -FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? EXCLAMATIONMARK? (KEYWORD_var / TypeExpr) +FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? EXCLAMATIONMARK? (KEYWORD_anytype / TypeExpr) VarDecl <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? LinkSection? (EQUAL Expr)? SEMICOLON @@ -10386,7 +10386,7 @@ LinkSection <- KEYWORD_linksection LPAREN Expr RPAREN ParamDecl <- (KEYWORD_noalias / KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType ParamType - <- KEYWORD_var + <- KEYWORD_anytype / DOT3 / TypeExpr @@ -10624,6 +10624,7 @@ KEYWORD_align <- 'align' end_of_word KEYWORD_allowzero <- 'allowzero' end_of_word KEYWORD_and <- 'and' end_of_word KEYWORD_anyframe <- 'anyframe' end_of_word +KEYWORD_anytype <- 'anytype' end_of_word KEYWORD_asm <- 'asm' end_of_word KEYWORD_async <- 'async' end_of_word KEYWORD_await <- 'await' end_of_word @@ -10669,14 +10670,14 @@ KEYWORD_var <- 'var' end_of_word KEYWORD_volatile <- 'volatile' end_of_word KEYWORD_while <- 'while' end_of_word -keyword <- KEYWORD_align / KEYWORD_and / KEYWORD_allowzero / KEYWORD_asm - / KEYWORD_async / KEYWORD_await / KEYWORD_break +keyword <- KEYWORD_align / KEYWORD_and / KEYWORD_anyframe / KEYWORD_anytype + / KEYWORD_allowzero / KEYWORD_asm / KEYWORD_async / KEYWORD_await / KEYWORD_break / KEYWORD_catch / KEYWORD_comptime / KEYWORD_const / KEYWORD_continue / KEYWORD_defer / KEYWORD_else / KEYWORD_enum / KEYWORD_errdefer / KEYWORD_error / KEYWORD_export / KEYWORD_extern / KEYWORD_false / KEYWORD_fn / KEYWORD_for / KEYWORD_if / KEYWORD_inline / KEYWORD_noalias / KEYWORD_null / KEYWORD_or - / KEYWORD_orelse / KEYWORD_packed / KEYWORD_anyframe / KEYWORD_pub + / KEYWORD_orelse / KEYWORD_packed / KEYWORD_pub / KEYWORD_resume / KEYWORD_return / KEYWORD_linksection / KEYWORD_struct / KEYWORD_suspend / KEYWORD_switch / KEYWORD_test / KEYWORD_threadlocal / KEYWORD_true / KEYWORD_try diff --git a/src/all_types.hpp b/src/all_types.hpp index 4465bf674c..a73efe2c82 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -692,7 +692,7 @@ enum NodeType { NodeTypeSuspend, NodeTypeAnyFrameType, NodeTypeEnumLiteral, - NodeTypeVarFieldType, + NodeTypeAnyTypeField, }; enum FnInline { @@ -705,7 +705,7 @@ struct AstNodeFnProto { Buf *name; ZigList params; AstNode *return_type; - Token *return_var_token; + Token *return_anytype_token; AstNode *fn_def_node; // populated if this is an extern declaration Buf *lib_name; @@ -734,7 +734,7 @@ struct AstNodeFnDef { struct AstNodeParamDecl { Buf *name; AstNode *type; - Token *var_token; + Token *anytype_token; Buf doc_comments; bool is_noalias; bool is_comptime; @@ -2145,7 +2145,7 @@ struct CodeGen { ZigType *entry_num_lit_float; ZigType *entry_undef; ZigType *entry_null; - ZigType *entry_var; + ZigType *entry_anytype; ZigType *entry_global_error_set; ZigType *entry_enum_literal; ZigType *entry_any_frame; diff --git a/src/analyze.cpp b/src/analyze.cpp index afe0fe6849..5eba515e68 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -1129,7 +1129,7 @@ ZigValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType * ZigValue *result = g->pass1_arena->create(); ZigValue *result_ptr = g->pass1_arena->create(); result->special = ConstValSpecialUndef; - result->type = (type_entry == nullptr) ? g->builtin_types.entry_var : type_entry; + result->type = (type_entry == nullptr) ? g->builtin_types.entry_anytype : type_entry; result_ptr->special = ConstValSpecialStatic; result_ptr->type = get_pointer_to_type(g, result->type, false); result_ptr->data.x_ptr.mut = ConstPtrMutComptimeVar; @@ -1230,7 +1230,7 @@ Error type_val_resolve_zero_bits(CodeGen *g, ZigValue *type_val, ZigType *parent Error type_val_resolve_is_opaque_type(CodeGen *g, ZigValue *type_val, bool *is_opaque_type) { if (type_val->special != ConstValSpecialLazy) { assert(type_val->special == ConstValSpecialStatic); - if (type_val->data.x_type == g->builtin_types.entry_var) { + if (type_val->data.x_type == g->builtin_types.entry_anytype) { *is_opaque_type = false; return ErrorNone; } @@ -1853,10 +1853,10 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc buf_sprintf("var args only allowed in functions with C calling convention")); return g->builtin_types.entry_invalid; } - } else if (param_node->data.param_decl.var_token != nullptr) { + } else if (param_node->data.param_decl.anytype_token != nullptr) { if (!calling_convention_allows_zig_types(fn_type_id.cc)) { add_node_error(g, param_node, - buf_sprintf("parameter of type 'var' not allowed in function with calling convention '%s'", + buf_sprintf("parameter of type 'anytype' not allowed in function with calling convention '%s'", calling_convention_name(fn_type_id.cc))); return g->builtin_types.entry_invalid; } @@ -1942,10 +1942,10 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc fn_entry->align_bytes = fn_type_id.alignment; } - if (fn_proto->return_var_token != nullptr) { + if (fn_proto->return_anytype_token != nullptr) { if (!calling_convention_allows_zig_types(fn_type_id.cc)) { add_node_error(g, fn_proto->return_type, - buf_sprintf("return type 'var' not allowed in function with calling convention '%s'", + buf_sprintf("return type 'anytype' not allowed in function with calling convention '%s'", calling_convention_name(fn_type_id.cc))); return g->builtin_types.entry_invalid; } @@ -3802,7 +3802,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) { case NodeTypeEnumLiteral: case NodeTypeAnyFrameType: case NodeTypeErrorSetField: - case NodeTypeVarFieldType: + case NodeTypeAnyTypeField: zig_unreachable(); } } @@ -5868,7 +5868,7 @@ ZigValue *get_the_one_possible_value(CodeGen *g, ZigType *type_entry) { ReqCompTime type_requires_comptime(CodeGen *g, ZigType *ty) { Error err; - if (ty == g->builtin_types.entry_var) { + if (ty == g->builtin_types.entry_anytype) { return ReqCompTimeYes; } switch (ty->id) { diff --git a/src/ast_render.cpp b/src/ast_render.cpp index 49fad80a40..ad308bf416 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -270,8 +270,8 @@ static const char *node_type_str(NodeType node_type) { return "EnumLiteral"; case NodeTypeErrorSetField: return "ErrorSetField"; - case NodeTypeVarFieldType: - return "VarFieldType"; + case NodeTypeAnyTypeField: + return "AnyTypeField"; } zig_unreachable(); } @@ -466,8 +466,8 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { } if (param_decl->data.param_decl.is_var_args) { fprintf(ar->f, "..."); - } else if (param_decl->data.param_decl.var_token != nullptr) { - fprintf(ar->f, "var"); + } else if (param_decl->data.param_decl.anytype_token != nullptr) { + fprintf(ar->f, "anytype"); } else { render_node_grouped(ar, param_decl->data.param_decl.type); } @@ -496,8 +496,8 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { fprintf(ar->f, ")"); } - if (node->data.fn_proto.return_var_token != nullptr) { - fprintf(ar->f, "var"); + if (node->data.fn_proto.return_anytype_token != nullptr) { + fprintf(ar->f, "anytype"); } else { AstNode *return_type_node = node->data.fn_proto.return_type; assert(return_type_node != nullptr); @@ -1216,8 +1216,8 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { fprintf(ar->f, ".%s", buf_ptr(&node->data.enum_literal.identifier->data.str_lit.str)); break; } - case NodeTypeVarFieldType: { - fprintf(ar->f, "var"); + case NodeTypeAnyTypeField: { + fprintf(ar->f, "anytype"); break; } case NodeTypeParamDecl: diff --git a/src/codegen.cpp b/src/codegen.cpp index 2f72861bc2..3473a2b0ac 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -8448,8 +8448,8 @@ static void define_builtin_types(CodeGen *g) { } { ZigType *entry = new_type_table_entry(ZigTypeIdOpaque); - buf_init_from_str(&entry->name, "(var)"); - g->builtin_types.entry_var = entry; + buf_init_from_str(&entry->name, "(anytype)"); + g->builtin_types.entry_anytype = entry; } for (size_t i = 0; i < array_length(c_int_type_infos); i += 1) { diff --git a/src/ir.cpp b/src/ir.cpp index ca0fd47c49..6447db8c71 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -9942,7 +9942,7 @@ static IrInstSrc *ir_gen_fn_proto(IrBuilderSrc *irb, Scope *parent_scope, AstNod is_var_args = true; break; } - if (param_node->data.param_decl.var_token == nullptr) { + if (param_node->data.param_decl.anytype_token == nullptr) { AstNode *type_node = param_node->data.param_decl.type; IrInstSrc *type_value = ir_gen_node(irb, type_node, parent_scope); if (type_value == irb->codegen->invalid_inst_src) @@ -9968,7 +9968,7 @@ static IrInstSrc *ir_gen_fn_proto(IrBuilderSrc *irb, Scope *parent_scope, AstNod } IrInstSrc *return_type; - if (node->data.fn_proto.return_var_token == nullptr) { + if (node->data.fn_proto.return_anytype_token == nullptr) { if (node->data.fn_proto.return_type == nullptr) { return_type = ir_build_const_type(irb, parent_scope, node, irb->codegen->builtin_types.entry_void); } else { @@ -10226,9 +10226,9 @@ static IrInstSrc *ir_gen_node_raw(IrBuilderSrc *irb, AstNode *node, Scope *scope add_node_error(irb->codegen, node, buf_sprintf("inferred array size invalid here")); return irb->codegen->invalid_inst_src; - case NodeTypeVarFieldType: + case NodeTypeAnyTypeField: return ir_lval_wrap(irb, scope, - ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_var), lval, result_loc); + ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_anytype), lval, result_loc); } zig_unreachable(); } @@ -10296,7 +10296,7 @@ static IrInstSrc *ir_gen_node_extra(IrBuilderSrc *irb, AstNode *node, Scope *sco case NodeTypeSuspend: case NodeTypeEnumLiteral: case NodeTypeInferredArrayType: - case NodeTypeVarFieldType: + case NodeTypeAnyTypeField: case NodeTypePrefixOpExpr: add_node_error(irb->codegen, node, buf_sprintf("invalid left-hand side to assignment")); @@ -10518,7 +10518,7 @@ ZigValue *const_ptr_pointee(IrAnalyze *ira, CodeGen *codegen, ZigValue *const_va if (val == nullptr) return nullptr; assert(const_val->type->id == ZigTypeIdPointer); ZigType *expected_type = const_val->type->data.pointer.child_type; - if (expected_type == codegen->builtin_types.entry_var) { + if (expected_type == codegen->builtin_types.entry_anytype) { return val; } switch (type_has_one_possible_value(codegen, expected_type)) { @@ -15040,7 +15040,7 @@ static IrInstGen *ir_analyze_cast(IrAnalyze *ira, IrInst *source_instr, } // This means the wanted type is anything. - if (wanted_type == ira->codegen->builtin_types.entry_var) { + if (wanted_type == ira->codegen->builtin_types.entry_anytype) { return value; } @@ -15635,7 +15635,7 @@ static IrInstGen *ir_implicit_cast(IrAnalyze *ira, IrInstGen *value, ZigType *ex static ZigType *get_ptr_elem_type(CodeGen *g, IrInstGen *ptr) { ir_assert_gen(ptr->value->type->id == ZigTypeIdPointer, ptr); ZigType *elem_type = ptr->value->type->data.pointer.child_type; - if (elem_type != g->builtin_types.entry_var) + if (elem_type != g->builtin_types.entry_anytype) return elem_type; if (ir_resolve_lazy(g, ptr->base.source_node, ptr->value)) @@ -15687,7 +15687,7 @@ static IrInstGen *ir_get_deref(IrAnalyze *ira, IrInst* source_instruction, IrIns } if (ptr->value->data.x_ptr.mut != ConstPtrMutRuntimeVar) { ZigValue *pointee = const_ptr_pointee_unchecked(ira->codegen, ptr->value); - if (child_type == ira->codegen->builtin_types.entry_var) { + if (child_type == ira->codegen->builtin_types.entry_anytype) { child_type = pointee->type; } if (pointee->special != ConstValSpecialRuntime) { @@ -19087,7 +19087,7 @@ static Error ir_result_has_type(IrAnalyze *ira, ResultLoc *result_loc, bool *out ZigType *dest_type = ir_resolve_type(ira, result_cast->base.source_instruction->child); if (type_is_invalid(dest_type)) return ErrorSemanticAnalyzeFail; - *out = (dest_type != ira->codegen->builtin_types.entry_var); + *out = (dest_type != ira->codegen->builtin_types.entry_anytype); return ErrorNone; } case ResultLocIdVar: @@ -19293,7 +19293,7 @@ static IrInstGen *ir_resolve_result_raw(IrAnalyze *ira, IrInst *suspend_source_i if (type_is_invalid(dest_type)) return ira->codegen->invalid_inst_gen; - if (dest_type == ira->codegen->builtin_types.entry_var) { + if (dest_type == ira->codegen->builtin_types.entry_anytype) { return ir_resolve_no_result_loc(ira, suspend_source_instr, result_loc, value_type); } @@ -19439,7 +19439,7 @@ static IrInstGen *ir_resolve_result_raw(IrAnalyze *ira, IrInst *suspend_source_i return ira->codegen->invalid_inst_gen; } - if (child_type != ira->codegen->builtin_types.entry_var) { + if (child_type != ira->codegen->builtin_types.entry_anytype) { if (type_size(ira->codegen, child_type) != type_size(ira->codegen, value_type)) { // pointer cast won't work; we need a temporary location. result_bit_cast->parent->written = parent_was_written; @@ -19600,9 +19600,9 @@ static IrInstGen *ir_analyze_instruction_resolve_result(IrAnalyze *ira, IrInstSr if (type_is_invalid(implicit_elem_type)) return ira->codegen->invalid_inst_gen; } else { - implicit_elem_type = ira->codegen->builtin_types.entry_var; + implicit_elem_type = ira->codegen->builtin_types.entry_anytype; } - if (implicit_elem_type == ira->codegen->builtin_types.entry_var) { + if (implicit_elem_type == ira->codegen->builtin_types.entry_anytype) { Buf *bare_name = buf_alloc(); Buf *name = get_anon_type_name(ira->codegen, nullptr, container_string(ContainerKindStruct), instruction->base.base.scope, instruction->base.base.source_node, bare_name); @@ -19759,7 +19759,7 @@ static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node assert(param_decl_node->type == NodeTypeParamDecl); IrInstGen *casted_arg; - if (param_decl_node->data.param_decl.var_token == nullptr) { + if (param_decl_node->data.param_decl.anytype_token == nullptr) { AstNode *param_type_node = param_decl_node->data.param_decl.type; ZigType *param_type = ir_analyze_type_expr(ira, *exec_scope, param_type_node); if (type_is_invalid(param_type)) @@ -19799,7 +19799,7 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod arg_part_of_generic_id = true; casted_arg = arg; } else { - if (param_decl_node->data.param_decl.var_token == nullptr) { + if (param_decl_node->data.param_decl.anytype_token == nullptr) { AstNode *param_type_node = param_decl_node->data.param_decl.type; ZigType *param_type = ir_analyze_type_expr(ira, *child_scope, param_type_node); if (type_is_invalid(param_type)) @@ -20011,7 +20011,7 @@ static IrInstGen *ir_analyze_store_ptr(IrAnalyze *ira, IrInst* source_instr, } if (ptr->value->type->data.pointer.inferred_struct_field != nullptr && - child_type == ira->codegen->builtin_types.entry_var) + child_type == ira->codegen->builtin_types.entry_anytype) { child_type = ptr->value->type->data.pointer.inferred_struct_field->inferred_struct_type; } @@ -20202,6 +20202,11 @@ static IrInstGen *ir_analyze_fn_call(IrAnalyze *ira, IrInst* source_instr, } AstNode *return_type_node = fn_proto_node->data.fn_proto.return_type; + if (return_type_node == nullptr) { + ir_add_error(ira, &fn_ref->base, + buf_sprintf("TODO implement inferred return types https://github.com/ziglang/zig/issues/447")); + return ira->codegen->invalid_inst_gen; + } ZigType *specified_return_type = ir_analyze_type_expr(ira, exec_scope, return_type_node); if (type_is_invalid(specified_return_type)) return ira->codegen->invalid_inst_gen; @@ -20364,7 +20369,7 @@ static IrInstGen *ir_analyze_fn_call(IrAnalyze *ira, IrInst* source_instr, inst_fn_type_id.alignment = align_bytes; } - if (fn_proto_node->data.fn_proto.return_var_token == nullptr) { + if (fn_proto_node->data.fn_proto.return_anytype_token == nullptr) { AstNode *return_type_node = fn_proto_node->data.fn_proto.return_type; ZigType *specified_return_type = ir_analyze_type_expr(ira, impl_fn->child_scope, return_type_node); if (type_is_invalid(specified_return_type)) @@ -20463,7 +20468,7 @@ static IrInstGen *ir_analyze_fn_call(IrAnalyze *ira, IrInst* source_instr, if (type_is_invalid(dummy_result->value->type)) return ira->codegen->invalid_inst_gen; ZigType *res_child_type = result_loc->value->type->data.pointer.child_type; - if (res_child_type == ira->codegen->builtin_types.entry_var) { + if (res_child_type == ira->codegen->builtin_types.entry_anytype) { res_child_type = impl_fn_type_id->return_type; } if (!handle_is_ptr(ira->codegen, res_child_type)) { @@ -20606,7 +20611,7 @@ static IrInstGen *ir_analyze_fn_call(IrAnalyze *ira, IrInst* source_instr, if (type_is_invalid(dummy_result->value->type)) return ira->codegen->invalid_inst_gen; ZigType *res_child_type = result_loc->value->type->data.pointer.child_type; - if (res_child_type == ira->codegen->builtin_types.entry_var) { + if (res_child_type == ira->codegen->builtin_types.entry_anytype) { res_child_type = return_type; } if (!handle_is_ptr(ira->codegen, res_child_type)) { @@ -22337,7 +22342,7 @@ static IrInstGen *ir_analyze_inferred_field_ptr(IrAnalyze *ira, Buf *field_name, inferred_struct_field->inferred_struct_type = container_type; inferred_struct_field->field_name = field_name; - ZigType *elem_type = ira->codegen->builtin_types.entry_var; + ZigType *elem_type = ira->codegen->builtin_types.entry_anytype; ZigType *field_ptr_type = get_pointer_to_type_extra2(ira->codegen, elem_type, container_ptr_type->data.pointer.is_const, container_ptr_type->data.pointer.is_volatile, PtrLenSingle, 0, 0, 0, false, VECTOR_INDEX_NONE, inferred_struct_field, nullptr); @@ -25115,7 +25120,7 @@ static ZigValue *create_ptr_like_type_info(IrAnalyze *ira, ZigType *ptr_type_ent fields[5]->special = ConstValSpecialStatic; fields[5]->type = ira->codegen->builtin_types.entry_bool; fields[5]->data.x_bool = attrs_type->data.pointer.allow_zero; - // sentinel: var + // sentinel: anytype ensure_field_index(result->type, "sentinel", 6); fields[6]->special = ConstValSpecialStatic; if (attrs_type->data.pointer.child_type->id != ZigTypeIdOpaque) { @@ -25243,7 +25248,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy fields[1]->special = ConstValSpecialStatic; fields[1]->type = ira->codegen->builtin_types.entry_type; fields[1]->data.x_type = type_entry->data.array.child_type; - // sentinel: var + // sentinel: anytype fields[2]->special = ConstValSpecialStatic; fields[2]->type = get_optional_type(ira->codegen, type_entry->data.array.child_type); fields[2]->data.x_optional = type_entry->data.array.sentinel; @@ -25598,7 +25603,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy inner_fields[2]->type = ira->codegen->builtin_types.entry_type; inner_fields[2]->data.x_type = struct_field->type_entry; - // default_value: var + // default_value: anytype inner_fields[3]->special = ConstValSpecialStatic; inner_fields[3]->type = get_optional_type2(ira->codegen, struct_field->type_entry); if (inner_fields[3]->type == nullptr) return ErrorSemanticAnalyzeFail; @@ -25736,7 +25741,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy ZigValue **fields = alloc_const_vals_ptrs(ira->codegen, 1); result->data.x_struct.fields = fields; ZigFn *fn = type_entry->data.frame.fn; - // function: var + // function: anytype ensure_field_index(result->type, "function", 0); fields[0] = create_const_fn(ira->codegen, fn); break; @@ -29996,7 +30001,7 @@ static IrInstGen *ir_analyze_instruction_arg_type(IrAnalyze *ira, IrInstSrcArgTy if (arg_index >= fn_type_id->param_count) { if (instruction->allow_var) { // TODO remove this with var args - return ir_const_type(ira, &instruction->base.base, ira->codegen->builtin_types.entry_var); + return ir_const_type(ira, &instruction->base.base, ira->codegen->builtin_types.entry_anytype); } ir_add_error(ira, &arg_index_inst->base, buf_sprintf("arg index %" ZIG_PRI_u64 " out of bounds; '%s' has %" ZIG_PRI_usize " arguments", @@ -30010,7 +30015,7 @@ static IrInstGen *ir_analyze_instruction_arg_type(IrAnalyze *ira, IrInstSrcArgTy ir_assert(fn_type->data.fn.is_generic, &instruction->base.base); if (instruction->allow_var) { - return ir_const_type(ira, &instruction->base.base, ira->codegen->builtin_types.entry_var); + return ir_const_type(ira, &instruction->base.base, ira->codegen->builtin_types.entry_anytype); } else { ir_add_error(ira, &arg_index_inst->base, buf_sprintf("@ArgType could not resolve the type of arg %" ZIG_PRI_u64 " because '%s' is generic", diff --git a/src/parser.cpp b/src/parser.cpp index c6c5823672..fcd1133b0d 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -786,7 +786,7 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod, B return nullptr; } -// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? EXCLAMATIONMARK? (KEYWORD_var / TypeExpr) +// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? EXCLAMATIONMARK? (KEYWORD_anytype / TypeExpr) static AstNode *ast_parse_fn_proto(ParseContext *pc) { Token *first = eat_token_if(pc, TokenIdKeywordFn); if (first == nullptr) { @@ -801,10 +801,10 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc) { AstNode *align_expr = ast_parse_byte_align(pc); AstNode *section_expr = ast_parse_link_section(pc); AstNode *callconv_expr = ast_parse_callconv(pc); - Token *var = eat_token_if(pc, TokenIdKeywordVar); + Token *anytype = eat_token_if(pc, TokenIdKeywordAnyType); Token *exmark = nullptr; AstNode *return_type = nullptr; - if (var == nullptr) { + if (anytype == nullptr) { exmark = eat_token_if(pc, TokenIdBang); return_type = ast_expect(pc, ast_parse_type_expr); } @@ -816,7 +816,7 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc) { res->data.fn_proto.align_expr = align_expr; res->data.fn_proto.section_expr = section_expr; res->data.fn_proto.callconv_expr = callconv_expr; - res->data.fn_proto.return_var_token = var; + res->data.fn_proto.return_anytype_token = anytype; res->data.fn_proto.auto_err_set = exmark != nullptr; res->data.fn_proto.return_type = return_type; @@ -870,9 +870,9 @@ static AstNode *ast_parse_container_field(ParseContext *pc) { AstNode *type_expr = nullptr; if (eat_token_if(pc, TokenIdColon) != nullptr) { - Token *var_tok = eat_token_if(pc, TokenIdKeywordVar); - if (var_tok != nullptr) { - type_expr = ast_create_node(pc, NodeTypeVarFieldType, var_tok); + Token *anytype_tok = eat_token_if(pc, TokenIdKeywordAnyType); + if (anytype_tok != nullptr) { + type_expr = ast_create_node(pc, NodeTypeAnyTypeField, anytype_tok); } else { type_expr = ast_expect(pc, ast_parse_type_expr); } @@ -2191,14 +2191,14 @@ static AstNode *ast_parse_param_decl(ParseContext *pc) { } // ParamType -// <- KEYWORD_var +// <- KEYWORD_anytype // / DOT3 // / TypeExpr static AstNode *ast_parse_param_type(ParseContext *pc) { - Token *var_token = eat_token_if(pc, TokenIdKeywordVar); - if (var_token != nullptr) { - AstNode *res = ast_create_node(pc, NodeTypeParamDecl, var_token); - res->data.param_decl.var_token = var_token; + Token *anytype_token = eat_token_if(pc, TokenIdKeywordAnyType); + if (anytype_token != nullptr) { + AstNode *res = ast_create_node(pc, NodeTypeParamDecl, anytype_token); + res->data.param_decl.anytype_token = anytype_token; return res; } @@ -3207,7 +3207,7 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont visit_field(&node->data.suspend.block, visit, context); break; case NodeTypeEnumLiteral: - case NodeTypeVarFieldType: + case NodeTypeAnyTypeField: break; } } diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index f09a146f2b..487a125d62 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -106,6 +106,7 @@ static const struct ZigKeyword zig_keywords[] = { {"allowzero", TokenIdKeywordAllowZero}, {"and", TokenIdKeywordAnd}, {"anyframe", TokenIdKeywordAnyFrame}, + {"anytype", TokenIdKeywordAnyType}, {"asm", TokenIdKeywordAsm}, {"async", TokenIdKeywordAsync}, {"await", TokenIdKeywordAwait}, @@ -1569,6 +1570,7 @@ const char * token_name(TokenId id) { case TokenIdKeywordAlign: return "align"; case TokenIdKeywordAnd: return "and"; case TokenIdKeywordAnyFrame: return "anyframe"; + case TokenIdKeywordAnyType: return "anytype"; case TokenIdKeywordAsm: return "asm"; case TokenIdKeywordBreak: return "break"; case TokenIdKeywordCatch: return "catch"; diff --git a/src/tokenizer.hpp b/src/tokenizer.hpp index 552ded4ef8..d8af21ee00 100644 --- a/src/tokenizer.hpp +++ b/src/tokenizer.hpp @@ -54,6 +54,7 @@ enum TokenId { TokenIdKeywordAllowZero, TokenIdKeywordAnd, TokenIdKeywordAnyFrame, + TokenIdKeywordAnyType, TokenIdKeywordAsm, TokenIdKeywordAsync, TokenIdKeywordAwait, -- cgit v1.2.3 From dff1ac1089dd8a7cae5c167bdb4e6269c9b84bb6 Mon Sep 17 00:00:00 2001 From: Vexu Date: Sat, 11 Jul 2020 12:08:29 +0300 Subject: check for invalid sentinel when creating pointer with `@Type` --- src/ir.cpp | 7 ++++++- test/compile_errors.zig | 16 ++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 6447db8c71..dc380b4389 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -25915,6 +25915,11 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI { return ira->codegen->invalid_inst_gen->value->type; } + if (sentinel != nullptr && (size_enum_index == BuiltinPtrSizeOne || size_enum_index == BuiltinPtrSizeC)) { + ir_add_error(ira, source_instr, + buf_sprintf("sentinels are only allowed on slices and unknown-length pointers")); + return ira->codegen->invalid_inst_gen->value->type; + } BigInt *bi = get_const_field_lit_int(ira, source_instr->source_node, payload, "alignment", 3); if (bi == nullptr) return ira->codegen->invalid_inst_gen->value->type; @@ -25948,7 +25953,7 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI 0, // host_int_bytes is_allowzero, VECTOR_INDEX_NONE, nullptr, sentinel); - if (size_enum_index != 2) + if (size_enum_index != BuiltinPtrSizeSlice) return ptr_type; return get_slice_type(ira->codegen, ptr_type); } diff --git a/test/compile_errors.zig b/test/compile_errors.zig index fb4428fbc6..5de56f8ca7 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -2,6 +2,22 @@ const tests = @import("tests.zig"); const std = @import("std"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.addTest("invalid pointer with @Type", + \\export fn entry() void { + \\ _ = @Type(.{ .Pointer = .{ + \\ .size = .One, + \\ .is_const = false, + \\ .is_volatile = false, + \\ .alignment = 1, + \\ .child = u8, + \\ .is_allowzero = false, + \\ .sentinel = 0, + \\ }}); + \\} + , &[_][]const u8{ + "tmp.zig:2:16: error: sentinels are only allowed on slices and unknown-length pointers", + }); + cases.addTest("int/float conversion to comptime_int/float", \\export fn foo() void { \\ var a: f32 = 2; -- cgit v1.2.3 From 4696cd3e09c4e33519dbb53a41c32bbdfd97f6f6 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 14 Jul 2020 14:38:40 -0700 Subject: fix ability to call methods on enums with pointer-to-self closes #3218 --- src/ir.cpp | 6 ++---- test/stage1/behavior/enum.zig | 19 +++++++++++++++++++ test/stage1/behavior/union.zig | 21 +++++++++++++++++++++ 3 files changed, 42 insertions(+), 4 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index dc380b4389..0dd8f4e86a 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -20182,7 +20182,7 @@ static IrInstGen *ir_analyze_fn_call(IrAnalyze *ira, IrInst* source_instr, } IrInstGen *first_arg; - if (!first_arg_known_bare && handle_is_ptr(ira->codegen, first_arg_ptr->value->type->data.pointer.child_type)) { + if (!first_arg_known_bare) { first_arg = first_arg_ptr; } else { first_arg = ir_get_deref(ira, &first_arg_ptr->base, first_arg_ptr, nullptr); @@ -20522,9 +20522,7 @@ static IrInstGen *ir_analyze_fn_call(IrAnalyze *ira, IrInst* source_instr, return ira->codegen->invalid_inst_gen; IrInstGen *first_arg; - if (param_type->id == ZigTypeIdPointer && - handle_is_ptr(ira->codegen, first_arg_ptr->value->type->data.pointer.child_type)) - { + if (param_type->id == ZigTypeIdPointer) { first_arg = first_arg_ptr; } else { first_arg = ir_get_deref(ira, &first_arg_ptr->base, first_arg_ptr, nullptr); diff --git a/test/stage1/behavior/enum.zig b/test/stage1/behavior/enum.zig index 765828f5ce..b9bb1db533 100644 --- a/test/stage1/behavior/enum.zig +++ b/test/stage1/behavior/enum.zig @@ -1140,3 +1140,22 @@ test "tagName on enum literals" { expect(mem.eql(u8, @tagName(.FooBar), "FooBar")); comptime expect(mem.eql(u8, @tagName(.FooBar), "FooBar")); } + +test "method call on an enum" { + const S = struct { + const E = enum { + one, + two, + + fn method(self: *E) bool { + return self.* == .two; + } + }; + fn doTheTest() void { + var e = E.two; + expect(e.method()); + } + }; + S.doTheTest(); + comptime S.doTheTest(); +} diff --git a/test/stage1/behavior/union.zig b/test/stage1/behavior/union.zig index da898347b9..cf3412eb5b 100644 --- a/test/stage1/behavior/union.zig +++ b/test/stage1/behavior/union.zig @@ -669,3 +669,24 @@ test "cast from anonymous struct to union" { S.doTheTest(); comptime S.doTheTest(); } + +test "method call on an empty union" { + const S = struct { + const MyUnion = union(Tag) { + pub const Tag = enum { X1, X2 }; + X1: [0]u8, + X2: [0]u8, + + pub fn useIt(self: *@This()) bool { + return true; + } + }; + + fn doTheTest() void { + var u = MyUnion{ .X1 = [0]u8{} }; + expect(u.useIt()); + } + }; + S.doTheTest(); + comptime S.doTheTest(); +} -- cgit v1.2.3 From a7c3cec65f1639195e787b98900c3f126953f880 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 14 Jul 2020 15:29:07 -0700 Subject: follow up from previous commit for generic methods --- src/ir.cpp | 2 +- test/stage1/behavior/enum.zig | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 0dd8f4e86a..e162125fb4 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -20317,7 +20317,7 @@ static IrInstGen *ir_analyze_fn_call(IrAnalyze *ira, IrInst* source_instr, } IrInstGen *first_arg; - if (!first_arg_known_bare && handle_is_ptr(ira->codegen, first_arg_ptr->value->type->data.pointer.child_type)) { + if (!first_arg_known_bare) { first_arg = first_arg_ptr; } else { first_arg = ir_get_deref(ira, &first_arg_ptr->base, first_arg_ptr, nullptr); diff --git a/test/stage1/behavior/enum.zig b/test/stage1/behavior/enum.zig index b9bb1db533..f569264520 100644 --- a/test/stage1/behavior/enum.zig +++ b/test/stage1/behavior/enum.zig @@ -1150,10 +1150,15 @@ test "method call on an enum" { fn method(self: *E) bool { return self.* == .two; } + + fn generic_method(self: *E, foo: anytype) bool { + return self.* == .two and foo == bool; + } }; fn doTheTest() void { var e = E.two; expect(e.method()); + expect(e.generic_method(bool)); } }; S.doTheTest(); -- cgit v1.2.3 From a1e78d0b0631885b95dfa80ab617818d1fd61277 Mon Sep 17 00:00:00 2001 From: Vexu Date: Thu, 16 Jul 2020 23:35:31 +0300 Subject: add is_tuple field to struct typeinfo part of #4335 --- lib/std/builtin.zig | 1 + lib/std/mem.zig | 5 ++--- src/ir.cpp | 8 +++++++- test/stage1/behavior/type_info.zig | 7 ++++++- 4 files changed, 16 insertions(+), 5 deletions(-) (limited to 'src/ir.cpp') diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 5eafc4e409..499011eab9 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -246,6 +246,7 @@ pub const TypeInfo = union(enum) { layout: ContainerLayout, fields: []const StructField, decls: []const Declaration, + is_tuple: bool, }; /// This data structure is used by the Zig language code generation and diff --git a/lib/std/mem.zig b/lib/std/mem.zig index f4489a4867..ac7bde47c1 100644 --- a/lib/std/mem.zig +++ b/lib/std/mem.zig @@ -709,8 +709,7 @@ pub fn zeroInit(comptime T: type, init: anytype) T { .Struct => |init_info| { var value = std.mem.zeroes(T); - // typeInfo won't tell us if this is a tuple - if (comptime eql(u8, init_info.fields[0].name, "0")) { + if (init_info.is_tuple) { inline for (init_info.fields) |field, i| { @field(value, struct_info.fields[i].name) = @field(init, field.name); } @@ -785,7 +784,7 @@ test "zeroInit" { a: u8, }; - const c = zeroInit(Color, .{255, 255}); + const c = zeroInit(Color, .{ 255, 255 }); testing.expectEqual(Color{ .r = 255, .g = 255, diff --git a/src/ir.cpp b/src/ir.cpp index e162125fb4..d027badac1 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -25546,7 +25546,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy result->special = ConstValSpecialStatic; result->type = ir_type_info_get_type(ira, "Struct", nullptr); - ZigValue **fields = alloc_const_vals_ptrs(ira->codegen, 3); + ZigValue **fields = alloc_const_vals_ptrs(ira->codegen, 4); result->data.x_struct.fields = fields; // layout: ContainerLayout @@ -25627,6 +25627,12 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy return err; } + // is_tuple: bool + ensure_field_index(result->type, "is_tuple", 3); + fields[3]->special = ConstValSpecialStatic; + fields[3]->type = ira->codegen->builtin_types.entry_bool; + fields[3]->data.x_bool = is_tuple(type_entry); + break; } case ZigTypeIdFn: diff --git a/test/stage1/behavior/type_info.zig b/test/stage1/behavior/type_info.zig index d4c8cec977..a79b3a1554 100644 --- a/test/stage1/behavior/type_info.zig +++ b/test/stage1/behavior/type_info.zig @@ -280,7 +280,7 @@ fn testFunction() void { expect(bound_fn_info.BoundFn.args[0].arg_type.? == *const TestStruct); } -extern fn foo(a: usize, b: bool, args: ...) usize; +extern fn foo(a: usize, b: bool, ...) usize; test "typeInfo with comptime parameter in struct fn def" { const S = struct { @@ -425,3 +425,8 @@ test "Declarations are returned in declaration order" { expect(std.mem.eql(u8, d[3].name, "d")); expect(std.mem.eql(u8, d[4].name, "e")); } + +test "Struct.is_tuple" { + expect(@typeInfo(@TypeOf(.{0})).Struct.is_tuple); + expect(!@typeInfo(@TypeOf(.{ .a = 0 })).Struct.is_tuple); +} -- cgit v1.2.3 From 78962eeeda07d613ebdfd239082268a6702c19db Mon Sep 17 00:00:00 2001 From: Vexu Date: Sat, 18 Jul 2020 10:22:15 +0300 Subject: fix floatCast type check regression Closes #5900 --- src/ir.cpp | 6 ++++++ test/compile_errors.zig | 12 ++++++++++++ 2 files changed, 18 insertions(+) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index d027badac1..88e111ccb5 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -26739,6 +26739,12 @@ static IrInstGen *ir_analyze_instruction_float_cast(IrAnalyze *ira, IrInstSrcFlo } } + if (target->value->type->id != ZigTypeIdFloat) { + ir_add_error(ira, &instruction->target->base, buf_sprintf("expected float type, found '%s'", + buf_ptr(&target->value->type->name))); + return ira->codegen->invalid_inst_gen; + } + if (instr_is_comptime(target) || dest_type->id == ZigTypeIdComptimeFloat) { ZigValue *val = ir_resolve_const(ira, target, UndefBad); if (val == nullptr) diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 5de56f8ca7..a1a261f887 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -122,6 +122,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ var a: u32 = 2; \\ _ = @floatToInt(u32, a); \\} + \\export fn qux() void { + \\ var a: f32 = 2; + \\ _ = @intCast(u32, a); + \\} , &[_][]const u8{ "tmp.zig:3:32: error: unable to evaluate constant expression", "tmp.zig:3:9: note: referenced here", @@ -129,6 +133,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:7:9: note: referenced here", "tmp.zig:11:26: error: expected float type, found 'u32'", "tmp.zig:11:9: note: referenced here", + "tmp.zig:15:23: error: expected integer type, found 'f32'", + "tmp.zig:15:9: note: referenced here", }); cases.addTest("invalid float casts", @@ -144,6 +150,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ var a: f32 = 2; \\ _ = @intToFloat(f32, a); \\} + \\export fn qux() void { + \\ var a: u32 = 2; + \\ _ = @floatCast(f32, a); + \\} , &[_][]const u8{ "tmp.zig:3:36: error: unable to evaluate constant expression", "tmp.zig:3:9: note: referenced here", @@ -151,6 +161,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:7:9: note: referenced here", "tmp.zig:11:26: error: expected int type, found 'f32'", "tmp.zig:11:9: note: referenced here", + "tmp.zig:15:25: error: expected float type, found 'u32'", + "tmp.zig:15:9: note: referenced here", }); cases.addTest("invalid assignments", -- cgit v1.2.3 From 596ca6cf70cf43c27e31bbcfc36bcdc70b13897a Mon Sep 17 00:00:00 2001 From: Vexu Date: Fri, 17 Jul 2020 20:16:23 +0300 Subject: allow non-pointer extern opaque variables --- src/analyze.cpp | 11 +++++++---- src/analyze.hpp | 2 +- src/ir.cpp | 2 +- test/stage1/behavior/misc.zig | 7 +++++++ 4 files changed, 16 insertions(+), 6 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/analyze.cpp b/src/analyze.cpp index 67c900507d..66f3f28b50 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -3823,15 +3823,18 @@ static Error resolve_decl_container(CodeGen *g, TldContainer *tld_container) { } } -ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry) { +ZigType *validate_var_type(CodeGen *g, AstNodeVariableDeclaration *source_node, ZigType *type_entry) { switch (type_entry->id) { case ZigTypeIdInvalid: return g->builtin_types.entry_invalid; + case ZigTypeIdOpaque: + if (source_node->is_extern) + return type_entry; + ZIG_FALLTHROUGH; case ZigTypeIdUnreachable: case ZigTypeIdUndefined: case ZigTypeIdNull: - case ZigTypeIdOpaque: - add_node_error(g, source_node, buf_sprintf("variable of type '%s' not allowed", + add_node_error(g, source_node->type, buf_sprintf("variable of type '%s' not allowed", buf_ptr(&type_entry->name))); return g->builtin_types.entry_invalid; case ZigTypeIdComptimeFloat: @@ -3973,7 +3976,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var, bool allow_lazy) { } else { tld_var->analyzing_type = true; ZigType *proposed_type = analyze_type_expr(g, tld_var->base.parent_scope, var_decl->type); - explicit_type = validate_var_type(g, var_decl->type, proposed_type); + explicit_type = validate_var_type(g, var_decl, proposed_type); } } diff --git a/src/analyze.hpp b/src/analyze.hpp index d75c967394..cb58aa6b74 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -77,7 +77,7 @@ void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node, bool all ZigType *get_src_ptr_type(ZigType *type); uint32_t get_ptr_align(CodeGen *g, ZigType *type); bool get_ptr_const(CodeGen *g, ZigType *type); -ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry); +ZigType *validate_var_type(CodeGen *g, AstNodeVariableDeclaration *source_node, ZigType *type_entry); ZigType *container_ref_type(ZigType *type_entry); bool type_is_complete(ZigType *type_entry); bool type_is_resolved(ZigType *type_entry, ResolveStatus status); diff --git a/src/ir.cpp b/src/ir.cpp index 88e111ccb5..11ff7746e7 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -18505,7 +18505,7 @@ static IrInstGen *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstSrcDeclV if (decl_var_instruction->var_type != nullptr) { var_type = decl_var_instruction->var_type->child; ZigType *proposed_type = ir_resolve_type(ira, var_type); - explicit_type = validate_var_type(ira->codegen, var_type->base.source_node, proposed_type); + explicit_type = validate_var_type(ira->codegen, &var->decl_node->data.variable_declaration, proposed_type); if (type_is_invalid(explicit_type)) { var->var_type = ira->codegen->builtin_types.entry_invalid; return ira->codegen->invalid_inst_gen; diff --git a/test/stage1/behavior/misc.zig b/test/stage1/behavior/misc.zig index 021dbe5602..57a9ba2576 100644 --- a/test/stage1/behavior/misc.zig +++ b/test/stage1/behavior/misc.zig @@ -713,3 +713,10 @@ test "auto created variables have correct alignment" { expect(S.foo("\x7a\x7a\x7a\x7a") == 0x7a7a7a7a); comptime expect(S.foo("\x7a\x7a\x7a\x7a") == 0x7a7a7a7a); } + +extern var opaque_extern_var: @Type(.Opaque); +var var_to_export: u32 = 42; +test "extern variable with non-pointer opaque type" { + @export(var_to_export, .{ .name = "opaque_extern_var" }); + expect(@ptrCast(*align(1) u32, &opaque_extern_var).* == 42); +} -- cgit v1.2.3