From b66438eb8092ea93b255f0ba11f857b1d6ccb052 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 28 May 2019 18:18:52 -0400 Subject: no "use of undeclared identifer" in dead comptime branches --- src/ir.cpp | 51 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 12 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 42b1acc4df..5d3cf5303c 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1015,6 +1015,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionHasDecl *) { return IrInstructionIdHasDecl; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionUndeclaredIdent *) { + return IrInstructionIdUndeclaredIdent; +} + template static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { T *special_instruction = allocate(1); @@ -3031,6 +3035,15 @@ static IrInstruction *ir_build_has_decl(IrBuilder *irb, Scope *scope, AstNode *s return &instruction->base; } +static IrInstruction *ir_build_undeclared_identifier(IrBuilder *irb, Scope *scope, AstNode *source_node, + Buf *name) +{ + IrInstructionUndeclaredIdent *instruction = ir_build_instruction(irb, scope, source_node); + instruction->name = name; + + return &instruction->base; +} + static IrInstruction *ir_build_check_runtime_scope(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *scope_is_comptime, IrInstruction *is_comptime) { IrInstructionCheckRuntimeScope *instruction = ir_build_instruction(irb, scope, source_node); instruction->scope_is_comptime = scope_is_comptime; @@ -3896,13 +3909,18 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node, Buf *variable_name = node->data.symbol_expr.symbol; - if (buf_eql_str(variable_name, "_") && lval == LValPtr) { - IrInstructionConst *const_instruction = ir_build_instruction(irb, scope, node); - const_instruction->base.value.type = get_pointer_to_type(irb->codegen, - irb->codegen->builtin_types.entry_void, false); - const_instruction->base.value.special = ConstValSpecialStatic; - const_instruction->base.value.data.x_ptr.special = ConstPtrSpecialDiscard; - return &const_instruction->base; + if (buf_eql_str(variable_name, "_")) { + if (lval == LValPtr) { + IrInstructionConst *const_instruction = ir_build_instruction(irb, scope, node); + const_instruction->base.value.type = get_pointer_to_type(irb->codegen, + irb->codegen->builtin_types.entry_void, false); + const_instruction->base.value.special = ConstValSpecialStatic; + const_instruction->base.value.data.x_ptr.special = ConstPtrSpecialDiscard; + return &const_instruction->base; + } else { + add_node_error(irb->codegen, node, buf_sprintf("`_` may only be used to assign things to")); + return irb->codegen->invalid_instruction; + } } ZigType *primitive_type; @@ -3943,11 +3961,7 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node, return irb->codegen->invalid_instruction; } - // put a variable of same name with invalid type in global scope - // so that future references to this same name will find a variable with an invalid type - populate_invalid_variable_in_scope(irb->codegen, scope, node, variable_name); - add_node_error(irb->codegen, node, buf_sprintf("use of undeclared identifier '%s'", buf_ptr(variable_name))); - return irb->codegen->invalid_instruction; + return ir_build_undeclared_identifier(irb, scope, node, variable_name); } static IrInstruction *ir_gen_array_access(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) { @@ -23237,6 +23251,16 @@ static IrInstruction *ir_analyze_instruction_has_decl(IrAnalyze *ira, IrInstruct return ir_const_bool(ira, &instruction->base, true); } +static IrInstruction *ir_analyze_instruction_undeclared_ident(IrAnalyze *ira, IrInstructionUndeclaredIdent *instruction) { + // put a variable of same name with invalid type in global scope + // so that future references to this same name will find a variable with an invalid type + populate_invalid_variable_in_scope(ira->codegen, instruction->base.scope, instruction->base.source_node, + instruction->name); + ir_add_error(ira, &instruction->base, + buf_sprintf("use of undeclared identifier '%s'", buf_ptr(instruction->name))); + return ira->codegen->invalid_instruction; +} + static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { switch (instruction->id) { case IrInstructionIdInvalid: @@ -23533,6 +23557,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio return ir_analyze_instruction_check_runtime_scope(ira, (IrInstructionCheckRuntimeScope *)instruction); case IrInstructionIdHasDecl: return ir_analyze_instruction_has_decl(ira, (IrInstructionHasDecl *)instruction); + case IrInstructionIdUndeclaredIdent: + return ir_analyze_instruction_undeclared_ident(ira, (IrInstructionUndeclaredIdent *)instruction); } zig_unreachable(); } @@ -23667,6 +23693,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdAssertNonNull: case IrInstructionIdResizeSlice: case IrInstructionIdGlobalAsm: + case IrInstructionIdUndeclaredIdent: return true; case IrInstructionIdPhi: -- cgit v1.2.3 From 1ccbd1fb67898c0691c74e65a7b9786fb5698619 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 29 May 2019 16:31:49 -0400 Subject: `use` works on unions and enums in addition to structs --- src/analyze.cpp | 23 ++++++++++++----------- src/analyze.hpp | 1 + src/ir.cpp | 10 ++-------- test/compile_errors.zig | 2 +- 4 files changed, 16 insertions(+), 20 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/analyze.cpp b/src/analyze.cpp index 3731f3b94c..182bcc93a6 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -3453,11 +3453,12 @@ TypeEnumField *find_enum_field_by_tag(ZigType *enum_type, const BigInt *tag) { } -static bool is_container(ZigType *type_entry) { +bool is_container(ZigType *type_entry) { switch (type_entry->id) { case ZigTypeIdInvalid: zig_unreachable(); case ZigTypeIdStruct: + return !type_entry->data.structure.is_slice; case ZigTypeIdEnum: case ZigTypeIdUnion: return true; @@ -3498,9 +3499,9 @@ bool is_array_ref(ZigType *type_entry) { return array->id == ZigTypeIdArray; } -bool is_container_ref(ZigType *type_entry) { - return is_ref(type_entry) ? - is_container(type_entry->data.pointer.child_type) : is_container(type_entry); +bool is_container_ref(ZigType *parent_ty) { + ZigType *ty = is_ref(parent_ty) ? parent_ty->data.pointer.child_type : parent_ty; + return is_slice(ty) || is_container(ty); } ZigType *container_ref_type(ZigType *type_entry) { @@ -3765,7 +3766,7 @@ static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry) { analyze_fn_ir(g, fn_table_entry, return_type_node); } -static void add_symbols_from_struct(CodeGen *g, AstNode *src_use_node, AstNode *dst_use_node, ScopeDecls* decls_scope) { +static void add_symbols_from_container(CodeGen *g, AstNode *src_use_node, AstNode *dst_use_node, ScopeDecls* decls_scope) { if (src_use_node->data.use.resolution == TldResolutionUnresolved) { preview_use_decl(g, src_use_node, decls_scope); } @@ -3784,9 +3785,9 @@ static void add_symbols_from_struct(CodeGen *g, AstNode *src_use_node, AstNode * ZigType *src_ty = use_expr->data.x_type; assert(src_ty); - if (src_ty->id != ZigTypeIdStruct || is_slice(src_ty)) { + if (!is_container(src_ty)) { add_node_error(g, dst_use_node, - buf_sprintf("expected struct, found '%s'", buf_ptr(&src_ty->name))); + buf_sprintf("expected struct, enum, or union; found '%s'", buf_ptr(&src_ty->name))); decls_scope->any_imports_failed = true; return; } @@ -3795,8 +3796,8 @@ static void add_symbols_from_struct(CodeGen *g, AstNode *src_use_node, AstNode * ScopeDecls *src_scope = get_container_scope(src_ty); // The top-level container where the symbols are defined, it's used in the // loop below in order to exclude the ones coming from an import statement - ZigType *src_import = get_scope_import(reinterpret_cast(src_scope)); - assert(src_import && src_import->id == ZigTypeIdStruct); + ZigType *src_import = get_scope_import(&src_scope->base); + assert(src_import != nullptr); if (src_scope->any_imports_failed) { decls_scope->any_imports_failed = true; @@ -3835,7 +3836,7 @@ static void add_symbols_from_struct(CodeGen *g, AstNode *src_use_node, AstNode * for (size_t i = 0; i < src_scope->use_decls.length; i += 1) { AstNode *use_decl_node = src_scope->use_decls.at(i); if (use_decl_node->data.use.visib_mod != VisibModPrivate) - add_symbols_from_struct(g, use_decl_node, dst_use_node, decls_scope); + add_symbols_from_container(g, use_decl_node, dst_use_node, decls_scope); } } @@ -3847,7 +3848,7 @@ void resolve_use_decl(CodeGen *g, AstNode *node, ScopeDecls *decls_scope) { { return; } - add_symbols_from_struct(g, node, node, decls_scope); + add_symbols_from_container(g, node, node, decls_scope); } void preview_use_decl(CodeGen *g, AstNode *node, ScopeDecls *decls_scope) { diff --git a/src/analyze.hpp b/src/analyze.hpp index a43b3063e0..d89bb91126 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -250,5 +250,6 @@ ZigLLVMDIType *get_llvm_di_type(CodeGen *g, ZigType *type); void add_cc_args(CodeGen *g, ZigList &args, const char *out_dep_path, bool translate_c); void src_assert(bool ok, AstNode *source_node); +bool is_container(ZigType *type_entry); #endif diff --git a/src/ir.cpp b/src/ir.cpp index 5d3cf5303c..fa60751ca5 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -10266,12 +10266,6 @@ static IrInstruction *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInstruc return result; } -static bool is_container(ZigType *type) { - return type->id == ZigTypeIdStruct || - type->id == ZigTypeIdEnum || - type->id == ZigTypeIdUnion; -} - static IrBasicBlock *ir_get_new_bb(IrAnalyze *ira, IrBasicBlock *old_bb, IrInstruction *ref_old_instruction) { assert(old_bb); @@ -16179,7 +16173,7 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc if (type_is_invalid(container_type)) { return ira->codegen->invalid_instruction; - } else if (is_container_ref(container_type)) { + } else if (is_slice(container_type) || is_container_ref(container_type)) { assert(container_ptr->value.type->id == ZigTypeIdPointer); if (container_type->id == ZigTypeIdPointer) { ZigType *bare_type = container_ref_type(container_type); @@ -16249,7 +16243,7 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc if (type_is_invalid(child_type)) { return ira->codegen->invalid_instruction; - } else if (is_container(child_type) && !is_slice(child_type)) { + } else if (is_container(child_type)) { if (child_type->id == ZigTypeIdEnum) { if ((err = ensure_complete_type(ira->codegen, child_type))) return ira->codegen->invalid_instruction; diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 7da5247d89..fbecacb94b 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -163,7 +163,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "usingnamespace with wrong type", \\use void; , - "tmp.zig:1:1: error: expected struct, found 'void'", + "tmp.zig:1:1: error: expected struct, enum, or union; found 'void'", ); cases.add( -- cgit v1.2.3 From 4188faeac56d9c022fa33449aa4283b1f55395cf Mon Sep 17 00:00:00 2001 From: Shawn Landden Date: Tue, 9 Apr 2019 15:00:53 -0500 Subject: stage1: AstNodes cannot be casted, but are rather accessed via a union. Unlike IrInstruction[Foo]s, which all start with: IrInstruction base; AstNodes do not work like this, and instead use a pointer to their specializations. The code assumed otherwise. --- src/ir.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index fa60751ca5..ba6f256b40 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -18507,7 +18507,7 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, IrInstruction *source_instr, return ErrorSemanticAnalyzeFail; } - AstNodeFnProto *fn_node = (AstNodeFnProto *)(fn_entry->proto_node); + AstNodeFnProto *fn_node = &fn_entry->proto_node->data.fn_proto; ConstExprValue *fn_def_val = create_const_vals(1); fn_def_val->special = ConstValSpecialStatic; -- cgit v1.2.3 From f9e7bd2682a83bad2b74686dd9b860fc2ce7ef8f Mon Sep 17 00:00:00 2001 From: tgschultz Date: Sun, 26 May 2019 21:22:45 +0000 Subject: std.meta/trait: def/definition => decl/declaration TypeInfo: defs/Definition => decls/Declarations --- doc/langref.html.in | 12 +-- src/codegen.cpp | 12 +-- src/ir.cpp | 176 ++++++++++++++++++------------------- std/fmt.zig | 18 +--- std/meta.zig | 44 +++++----- std/meta/trait.zig | 48 ++-------- test/stage1/behavior/type_info.zig | 16 ++-- 7 files changed, 136 insertions(+), 190 deletions(-) (limited to 'src/ir.cpp') diff --git a/doc/langref.html.in b/doc/langref.html.in index d583e02b1b..68f3926839 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -7545,7 +7545,7 @@ pub const TypeInfo = union(TypeId) { pub const Struct = struct { layout: ContainerLayout, fields: []StructField, - defs: []Definition, + decls: []Declaration, }; pub const Optional = struct { @@ -7573,7 +7573,7 @@ pub const TypeInfo = union(TypeId) { layout: ContainerLayout, tag_type: type, fields: []EnumField, - defs: []Definition, + decls: []Declaration, }; pub const UnionField = struct { @@ -7586,7 +7586,7 @@ pub const TypeInfo = union(TypeId) { layout: ContainerLayout, tag_type: ?type, fields: []UnionField, - defs: []Definition, + decls: []Declaration, }; pub const CallingConvention = enum { @@ -7622,7 +7622,7 @@ pub const TypeInfo = union(TypeId) { child: type, }; - pub const Definition = struct { + pub const Declaration = struct { name: []const u8, is_pub: bool, data: Data, @@ -7630,9 +7630,9 @@ pub const TypeInfo = union(TypeId) { pub const Data = union(enum) { Type: type, Var: type, - Fn: FnDef, + Fn: FnDecl, - pub const FnDef = struct { + pub const FnDecl = struct { fn_type: type, inline_type: Inline, calling_convention: CallingConvention, diff --git a/src/codegen.cpp b/src/codegen.cpp index fc9cdfc9b8..826a9463ac 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -7762,7 +7762,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { " pub const Struct = struct {\n" " layout: ContainerLayout,\n" " fields: []StructField,\n" - " defs: []Definition,\n" + " decls: []Declaration,\n" " };\n" "\n" " pub const Optional = struct {\n" @@ -7790,7 +7790,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { " layout: ContainerLayout,\n" " tag_type: type,\n" " fields: []EnumField,\n" - " defs: []Definition,\n" + " decls: []Declaration,\n" " };\n" "\n" " pub const UnionField = struct {\n" @@ -7803,7 +7803,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { " layout: ContainerLayout,\n" " tag_type: ?type,\n" " fields: []UnionField,\n" - " defs: []Definition,\n" + " decls: []Declaration,\n" " };\n" "\n" " pub const CallingConvention = enum {\n" @@ -7839,7 +7839,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { " child: type,\n" " };\n" "\n" - " pub const Definition = struct {\n" + " pub const Declaration = struct {\n" " name: []const u8,\n" " is_pub: bool,\n" " data: Data,\n" @@ -7847,9 +7847,9 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { " pub const Data = union(enum) {\n" " Type: type,\n" " Var: type,\n" - " Fn: FnDef,\n" + " Fn: FnDecl,\n" "\n" - " pub const FnDef = struct {\n" + " pub const FnDecl = struct {\n" " fn_type: type,\n" " inline_type: Inline,\n" " calling_convention: CallingConvention,\n" diff --git a/src/ir.cpp b/src/ir.cpp index ba6f256b40..c4c3808545 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -18380,37 +18380,37 @@ static ZigType *ir_type_info_get_type(IrAnalyze *ira, const char *type_name, Zig return var->const_value->data.x_type; } -static Error ir_make_type_info_defs(IrAnalyze *ira, IrInstruction *source_instr, ConstExprValue *out_val, +static Error ir_make_type_info_decls(IrAnalyze *ira, IrInstruction *source_instr, ConstExprValue *out_val, ScopeDecls *decls_scope) { Error err; - ZigType *type_info_definition_type = ir_type_info_get_type(ira, "Definition", nullptr); - if ((err = type_resolve(ira->codegen, type_info_definition_type, ResolveStatusSizeKnown))) + ZigType *type_info_declaration_type = ir_type_info_get_type(ira, "Declaration", nullptr); + if ((err = type_resolve(ira->codegen, type_info_declaration_type, ResolveStatusSizeKnown))) return err; - ensure_field_index(type_info_definition_type, "name", 0); - ensure_field_index(type_info_definition_type, "is_pub", 1); - ensure_field_index(type_info_definition_type, "data", 2); + ensure_field_index(type_info_declaration_type, "name", 0); + ensure_field_index(type_info_declaration_type, "is_pub", 1); + ensure_field_index(type_info_declaration_type, "data", 2); - ZigType *type_info_definition_data_type = ir_type_info_get_type(ira, "Data", type_info_definition_type); - if ((err = ensure_complete_type(ira->codegen, type_info_definition_data_type))) + ZigType *type_info_declaration_data_type = ir_type_info_get_type(ira, "Data", type_info_declaration_type); + if ((err = ensure_complete_type(ira->codegen, type_info_declaration_data_type))) return err; - ZigType *type_info_fn_def_type = ir_type_info_get_type(ira, "FnDef", type_info_definition_data_type); - if ((err = ensure_complete_type(ira->codegen, type_info_fn_def_type))) + ZigType *type_info_fn_decl_type = ir_type_info_get_type(ira, "FnDecl", type_info_declaration_data_type); + if ((err = ensure_complete_type(ira->codegen, type_info_fn_decl_type))) return err; - ZigType *type_info_fn_def_inline_type = ir_type_info_get_type(ira, "Inline", type_info_fn_def_type); - if ((err = ensure_complete_type(ira->codegen, type_info_fn_def_inline_type))) + ZigType *type_info_fn_decl_inline_type = ir_type_info_get_type(ira, "Inline", type_info_fn_decl_type); + if ((err = ensure_complete_type(ira->codegen, type_info_fn_decl_inline_type))) return err; - // Loop through our definitions once to figure out how many definitions we will generate info for. + // Loop through our declarations once to figure out how many declarations we will generate info for. auto decl_it = decls_scope->decl_table.entry_iterator(); decltype(decls_scope->decl_table)::Entry *curr_entry = nullptr; - int definition_count = 0; + int declaration_count = 0; while ((curr_entry = decl_it.next()) != nullptr) { - // If the definition is unresolved, force it to be resolved again. + // If the declaration is unresolved, force it to be resolved again. if (curr_entry->value->resolution == TldResolutionUnresolved) { resolve_top_level_decl(ira->codegen, curr_entry->value, curr_entry->value->source_node); if (curr_entry->value->resolution != TldResolutionOk) { @@ -18426,21 +18426,21 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, IrInstruction *source_instr, continue; } - definition_count += 1; + declaration_count += 1; } } - ConstExprValue *definition_array = create_const_vals(1); - definition_array->special = ConstValSpecialStatic; - definition_array->type = get_array_type(ira->codegen, type_info_definition_type, definition_count); - definition_array->data.x_array.special = ConstArraySpecialNone; - definition_array->data.x_array.data.s_none.elements = create_const_vals(definition_count); - init_const_slice(ira->codegen, out_val, definition_array, 0, definition_count, false); + ConstExprValue *declaration_array = create_const_vals(1); + declaration_array->special = ConstValSpecialStatic; + declaration_array->type = get_array_type(ira->codegen, type_info_declaration_type, declaration_count); + declaration_array->data.x_array.special = ConstArraySpecialNone; + declaration_array->data.x_array.data.s_none.elements = create_const_vals(declaration_count); + init_const_slice(ira->codegen, out_val, declaration_array, 0, declaration_count, false); - // Loop through the definitions and generate info. + // Loop through the declarations and generate info. decl_it = decls_scope->decl_table.entry_iterator(); curr_entry = nullptr; - int definition_index = 0; + int declaration_index = 0; while ((curr_entry = decl_it.next()) != nullptr) { // Skip comptime blocks and test functions. if (curr_entry->value->id == TldIdCompTime) { @@ -18451,10 +18451,10 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, IrInstruction *source_instr, continue; } - ConstExprValue *definition_val = &definition_array->data.x_array.data.s_none.elements[definition_index]; + ConstExprValue *declaration_val = &declaration_array->data.x_array.data.s_none.elements[declaration_index]; - definition_val->special = ConstValSpecialStatic; - definition_val->type = type_info_definition_type; + declaration_val->special = ConstValSpecialStatic; + declaration_val->type = type_info_declaration_type; ConstExprValue *inner_fields = create_const_vals(3); ConstExprValue *name = create_const_str_lit(ira->codegen, curr_entry->key); @@ -18463,9 +18463,9 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, IrInstruction *source_instr, inner_fields[1].type = ira->codegen->builtin_types.entry_bool; inner_fields[1].data.x_bool = curr_entry->value->visib_mod == VisibModPub; inner_fields[2].special = ConstValSpecialStatic; - inner_fields[2].type = type_info_definition_data_type; + inner_fields[2].type = type_info_declaration_data_type; inner_fields[2].parent.id = ConstParentIdStruct; - inner_fields[2].parent.data.p_struct.struct_val = definition_val; + inner_fields[2].parent.data.p_struct.struct_val = declaration_val; inner_fields[2].parent.data.p_struct.field_index = 1; switch (curr_entry->value->id) { @@ -18476,7 +18476,7 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, IrInstruction *source_instr, return ErrorSemanticAnalyzeFail; if (var->const_value->type->id == ZigTypeIdMetaType) { - // We have a variable of type 'type', so it's actually a type definition. + // We have a variable of type 'type', so it's actually a type declaration. // 0: Data.Type: type bigint_init_unsigned(&inner_fields[2].data.x_union.tag, 0); inner_fields[2].data.x_union.payload = var->const_value; @@ -18496,7 +18496,7 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, IrInstruction *source_instr, } case TldIdFn: { - // 2: Data.Fn: Data.FnDef + // 2: Data.Fn: Data.FnDecl bigint_init_unsigned(&inner_fields[2].data.x_union.tag, 2); ZigFn *fn_entry = ((TldFn *)curr_entry->value)->fn_entry; @@ -18509,68 +18509,68 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, IrInstruction *source_instr, AstNodeFnProto *fn_node = &fn_entry->proto_node->data.fn_proto; - ConstExprValue *fn_def_val = create_const_vals(1); - fn_def_val->special = ConstValSpecialStatic; - fn_def_val->type = type_info_fn_def_type; - fn_def_val->parent.id = ConstParentIdUnion; - fn_def_val->parent.data.p_union.union_val = &inner_fields[2]; + ConstExprValue *fn_decl_val = create_const_vals(1); + fn_decl_val->special = ConstValSpecialStatic; + fn_decl_val->type = type_info_fn_decl_type; + fn_decl_val->parent.id = ConstParentIdUnion; + fn_decl_val->parent.data.p_union.union_val = &inner_fields[2]; - ConstExprValue *fn_def_fields = create_const_vals(9); - fn_def_val->data.x_struct.fields = fn_def_fields; + ConstExprValue *fn_decl_fields = create_const_vals(9); + fn_decl_val->data.x_struct.fields = fn_decl_fields; // fn_type: type - ensure_field_index(fn_def_val->type, "fn_type", 0); - fn_def_fields[0].special = ConstValSpecialStatic; - fn_def_fields[0].type = ira->codegen->builtin_types.entry_type; - fn_def_fields[0].data.x_type = fn_entry->type_entry; - // inline_type: Data.FnDef.Inline - ensure_field_index(fn_def_val->type, "inline_type", 1); - fn_def_fields[1].special = ConstValSpecialStatic; - fn_def_fields[1].type = type_info_fn_def_inline_type; - bigint_init_unsigned(&fn_def_fields[1].data.x_enum_tag, fn_entry->fn_inline); + ensure_field_index(fn_decl_val->type, "fn_type", 0); + fn_decl_fields[0].special = ConstValSpecialStatic; + fn_decl_fields[0].type = ira->codegen->builtin_types.entry_type; + fn_decl_fields[0].data.x_type = fn_entry->type_entry; + // inline_type: Data.FnDecl.Inline + ensure_field_index(fn_decl_val->type, "inline_type", 1); + fn_decl_fields[1].special = ConstValSpecialStatic; + fn_decl_fields[1].type = type_info_fn_decl_inline_type; + bigint_init_unsigned(&fn_decl_fields[1].data.x_enum_tag, fn_entry->fn_inline); // calling_convention: TypeInfo.CallingConvention - ensure_field_index(fn_def_val->type, "calling_convention", 2); - fn_def_fields[2].special = ConstValSpecialStatic; - fn_def_fields[2].type = ir_type_info_get_type(ira, "CallingConvention", nullptr); - bigint_init_unsigned(&fn_def_fields[2].data.x_enum_tag, fn_node->cc); + ensure_field_index(fn_decl_val->type, "calling_convention", 2); + fn_decl_fields[2].special = ConstValSpecialStatic; + fn_decl_fields[2].type = ir_type_info_get_type(ira, "CallingConvention", nullptr); + bigint_init_unsigned(&fn_decl_fields[2].data.x_enum_tag, fn_node->cc); // is_var_args: bool - ensure_field_index(fn_def_val->type, "is_var_args", 3); + ensure_field_index(fn_decl_val->type, "is_var_args", 3); bool is_varargs = fn_node->is_var_args; - fn_def_fields[3].special = ConstValSpecialStatic; - fn_def_fields[3].type = ira->codegen->builtin_types.entry_bool; - fn_def_fields[3].data.x_bool = is_varargs; + fn_decl_fields[3].special = ConstValSpecialStatic; + fn_decl_fields[3].type = ira->codegen->builtin_types.entry_bool; + fn_decl_fields[3].data.x_bool = is_varargs; // is_extern: bool - ensure_field_index(fn_def_val->type, "is_extern", 4); - fn_def_fields[4].special = ConstValSpecialStatic; - fn_def_fields[4].type = ira->codegen->builtin_types.entry_bool; - fn_def_fields[4].data.x_bool = fn_node->is_extern; + ensure_field_index(fn_decl_val->type, "is_extern", 4); + fn_decl_fields[4].special = ConstValSpecialStatic; + fn_decl_fields[4].type = ira->codegen->builtin_types.entry_bool; + fn_decl_fields[4].data.x_bool = fn_node->is_extern; // is_export: bool - ensure_field_index(fn_def_val->type, "is_export", 5); - fn_def_fields[5].special = ConstValSpecialStatic; - fn_def_fields[5].type = ira->codegen->builtin_types.entry_bool; - fn_def_fields[5].data.x_bool = fn_node->is_export; + ensure_field_index(fn_decl_val->type, "is_export", 5); + fn_decl_fields[5].special = ConstValSpecialStatic; + fn_decl_fields[5].type = ira->codegen->builtin_types.entry_bool; + fn_decl_fields[5].data.x_bool = fn_node->is_export; // lib_name: ?[]const u8 - ensure_field_index(fn_def_val->type, "lib_name", 6); - fn_def_fields[6].special = ConstValSpecialStatic; + ensure_field_index(fn_decl_val->type, "lib_name", 6); + fn_decl_fields[6].special = ConstValSpecialStatic; ZigType *u8_ptr = get_pointer_to_type_extra( ira->codegen, ira->codegen->builtin_types.entry_u8, true, false, PtrLenUnknown, 0, 0, 0, false); - fn_def_fields[6].type = get_optional_type(ira->codegen, get_slice_type(ira->codegen, u8_ptr)); + fn_decl_fields[6].type = get_optional_type(ira->codegen, get_slice_type(ira->codegen, u8_ptr)); if (fn_node->is_extern && buf_len(fn_node->lib_name) > 0) { - fn_def_fields[6].data.x_optional = create_const_vals(1); + fn_decl_fields[6].data.x_optional = create_const_vals(1); ConstExprValue *lib_name = create_const_str_lit(ira->codegen, fn_node->lib_name); - init_const_slice(ira->codegen, fn_def_fields[6].data.x_optional, lib_name, 0, buf_len(fn_node->lib_name), true); + init_const_slice(ira->codegen, fn_decl_fields[6].data.x_optional, lib_name, 0, buf_len(fn_node->lib_name), true); } else { - fn_def_fields[6].data.x_optional = nullptr; + fn_decl_fields[6].data.x_optional = nullptr; } // return_type: type - ensure_field_index(fn_def_val->type, "return_type", 7); - fn_def_fields[7].special = ConstValSpecialStatic; - fn_def_fields[7].type = ira->codegen->builtin_types.entry_type; - fn_def_fields[7].data.x_type = fn_entry->type_entry->data.fn.fn_type_id.return_type; + ensure_field_index(fn_decl_val->type, "return_type", 7); + fn_decl_fields[7].special = ConstValSpecialStatic; + fn_decl_fields[7].type = ira->codegen->builtin_types.entry_type; + fn_decl_fields[7].data.x_type = fn_entry->type_entry->data.fn.fn_type_id.return_type; // arg_names: [][] const u8 - ensure_field_index(fn_def_val->type, "arg_names", 8); + ensure_field_index(fn_decl_val->type, "arg_names", 8); size_t fn_arg_count = fn_entry->variable_list.length; ConstExprValue *fn_arg_name_array = create_const_vals(1); fn_arg_name_array->special = ConstValSpecialStatic; @@ -18579,7 +18579,7 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, IrInstruction *source_instr, fn_arg_name_array->data.x_array.special = ConstArraySpecialNone; fn_arg_name_array->data.x_array.data.s_none.elements = create_const_vals(fn_arg_count); - init_const_slice(ira->codegen, &fn_def_fields[8], fn_arg_name_array, 0, fn_arg_count, false); + init_const_slice(ira->codegen, &fn_decl_fields[8], fn_arg_name_array, 0, fn_arg_count, false); for (size_t fn_arg_index = 0; fn_arg_index < fn_arg_count; fn_arg_index++) { ZigVar *arg_var = fn_entry->variable_list.at(fn_arg_index); @@ -18591,7 +18591,7 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, IrInstruction *source_instr, fn_arg_name_val->parent.data.p_array.elem_index = fn_arg_index; } - inner_fields[2].data.x_union.payload = fn_def_val; + inner_fields[2].data.x_union.payload = fn_decl_val; break; } case TldIdContainer: @@ -18615,11 +18615,11 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, IrInstruction *source_instr, zig_unreachable(); } - definition_val->data.x_struct.fields = inner_fields; - definition_index++; + declaration_val->data.x_struct.fields = inner_fields; + declaration_index++; } - assert(definition_index == definition_count); + assert(declaration_index == declaration_count); return ErrorNone; } @@ -18927,9 +18927,9 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr enum_field_val->parent.data.p_array.array_val = enum_field_array; enum_field_val->parent.data.p_array.elem_index = enum_field_index; } - // defs: []TypeInfo.Definition - ensure_field_index(result->type, "defs", 3); - if ((err = ir_make_type_info_defs(ira, source_instr, &fields[3], + // decls: []TypeInfo.Declaration + ensure_field_index(result->type, "decls", 3); + if ((err = ir_make_type_info_decls(ira, source_instr, &fields[3], type_entry->data.enumeration.decls_scope))) { return err; @@ -19094,9 +19094,9 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr union_field_val->parent.data.p_array.array_val = union_field_array; union_field_val->parent.data.p_array.elem_index = union_field_index; } - // defs: []TypeInfo.Definition - ensure_field_index(result->type, "defs", 3); - if ((err = ir_make_type_info_defs(ira, source_instr, &fields[3], + // decls: []TypeInfo.Declaration + ensure_field_index(result->type, "decls", 3); + if ((err = ir_make_type_info_decls(ira, source_instr, &fields[3], type_entry->data.unionation.decls_scope))) { return err; @@ -19175,9 +19175,9 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr struct_field_val->parent.data.p_array.array_val = struct_field_array; struct_field_val->parent.data.p_array.elem_index = struct_field_index; } - // defs: []TypeInfo.Definition - ensure_field_index(result->type, "defs", 2); - if ((err = ir_make_type_info_defs(ira, source_instr, &fields[2], + // decls: []TypeInfo.Declaration + ensure_field_index(result->type, "decls", 2); + if ((err = ir_make_type_info_decls(ira, source_instr, &fields[2], type_entry->data.structure.decls_scope))) { return err; diff --git a/std/fmt.zig b/std/fmt.zig index 74c36f7086..c663530866 100644 --- a/std/fmt.zig +++ b/std/fmt.zig @@ -145,23 +145,7 @@ pub fn formatType( return format(context, Errors, output, "promise@{x}", @ptrToInt(value)); }, builtin.TypeId.Enum, builtin.TypeId.Union, builtin.TypeId.Struct => { - const has_cust_fmt = comptime cf: { - const info = @typeInfo(T); - const defs = switch (info) { - builtin.TypeId.Struct => |s| s.defs, - builtin.TypeId.Union => |u| u.defs, - builtin.TypeId.Enum => |e| e.defs, - else => unreachable, - }; - - for (defs) |def| { - if (mem.eql(u8, def.name, "format")) { - break :cf true; - } - } - break :cf false; - }; - if (has_cust_fmt) return value.format(fmt, context, Errors, output); + if (comptime std.meta.trait.hasFn("format")(T)) return value.format(fmt, context, Errors, output); try output(context, @typeName(T)); switch (comptime @typeId(T)) { diff --git a/std/meta.zig b/std/meta.zig index a8c7e4b415..297b55894e 100644 --- a/std/meta.zig +++ b/std/meta.zig @@ -160,16 +160,16 @@ test "std.meta.containerLayout" { testing.expect(containerLayout(U3) == TypeInfo.ContainerLayout.Extern); } -pub fn definitions(comptime T: type) []TypeInfo.Definition { +pub fn declarations(comptime T: type) []TypeInfo.Declaration { return switch (@typeInfo(T)) { - TypeId.Struct => |info| info.defs, - TypeId.Enum => |info| info.defs, - TypeId.Union => |info| info.defs, + TypeId.Struct => |info| info.decls, + TypeId.Enum => |info| info.decls, + TypeId.Union => |info| info.decls, else => @compileError("Expected struct, enum or union type, found '" ++ @typeName(T) ++ "'"), }; } -test "std.meta.definitions" { +test "std.meta.declarations" { const E1 = enum { A, @@ -184,28 +184,28 @@ test "std.meta.definitions" { fn a() void {} }; - const defs = comptime [][]TypeInfo.Definition{ - definitions(E1), - definitions(S1), - definitions(U1), + const decls = comptime [][]TypeInfo.Declaration{ + declarations(E1), + declarations(S1), + declarations(U1), }; - inline for (defs) |def| { - testing.expect(def.len == 1); - testing.expect(comptime mem.eql(u8, def[0].name, "a")); + inline for (decls) |decl| { + testing.expect(decl.len == 1); + testing.expect(comptime mem.eql(u8, decl[0].name, "a")); } } -pub fn definitionInfo(comptime T: type, comptime def_name: []const u8) TypeInfo.Definition { - inline for (comptime definitions(T)) |def| { - if (comptime mem.eql(u8, def.name, def_name)) - return def; +pub fn declarationInfo(comptime T: type, comptime decl_name: []const u8) TypeInfo.Declaration { + inline for (comptime declarations(T)) |decl| { + if (comptime mem.eql(u8, decl.name, decl_name)) + return decl; } - @compileError("'" ++ @typeName(T) ++ "' has no definition '" ++ def_name ++ "'"); + @compileError("'" ++ @typeName(T) ++ "' has no declaration '" ++ decl_name ++ "'"); } -test "std.meta.definitionInfo" { +test "std.meta.declarationInfo" { const E1 = enum { A, @@ -220,10 +220,10 @@ test "std.meta.definitionInfo" { fn a() void {} }; - const infos = comptime []TypeInfo.Definition{ - definitionInfo(E1, "a"), - definitionInfo(S1, "a"), - definitionInfo(U1, "a"), + const infos = comptime []TypeInfo.Declaration{ + declarationInfo(E1, "a"), + declarationInfo(S1, "a"), + declarationInfo(U1, "a"), }; inline for (infos) |info| { diff --git a/std/meta/trait.zig b/std/meta/trait.zig index f77619ec39..db3e52fc3f 100644 --- a/std/meta/trait.zig +++ b/std/meta/trait.zig @@ -55,53 +55,15 @@ test "std.meta.trait.multiTrait" { testing.expect(!isVector(u8)); } -/// -pub fn hasDef(comptime name: []const u8) TraitFn { - const Closure = struct { - pub fn trait(comptime T: type) bool { - const info = @typeInfo(T); - const defs = switch (info) { - builtin.TypeId.Struct => |s| s.defs, - builtin.TypeId.Union => |u| u.defs, - builtin.TypeId.Enum => |e| e.defs, - else => return false, - }; - - inline for (defs) |def| { - if (mem.eql(u8, def.name, name)) return def.is_pub; - } - - return false; - } - }; - return Closure.trait; -} - -test "std.meta.trait.hasDef" { - const TestStruct = struct { - pub const value = u8(16); - }; - - const TestStructFail = struct { - const value = u8(16); - }; - - testing.expect(hasDef("value")(TestStruct)); - testing.expect(!hasDef("value")(TestStructFail)); - testing.expect(!hasDef("value")(*TestStruct)); - testing.expect(!hasDef("value")(**TestStructFail)); - testing.expect(!hasDef("x")(TestStruct)); - testing.expect(!hasDef("value")(u8)); -} - /// pub fn hasFn(comptime name: []const u8) TraitFn { const Closure = struct { pub fn trait(comptime T: type) bool { - if (!comptime hasDef(name)(T)) return false; - const DefType = @typeOf(@field(T, name)); - const def_type_id = @typeId(DefType); - return def_type_id == builtin.TypeId.Fn; + if (!comptime isContainer(T)) return false; + if (!comptime @hasDecl(T, name)) return false; + const DeclType = @typeOf(@field(T, name)); + const decl_type_id = @typeId(DeclType); + return decl_type_id == builtin.TypeId.Fn; } }; return Closure.trait; diff --git a/test/stage1/behavior/type_info.zig b/test/stage1/behavior/type_info.zig index 2d088fa261..f05b02e7ab 100644 --- a/test/stage1/behavior/type_info.zig +++ b/test/stage1/behavior/type_info.zig @@ -177,7 +177,7 @@ fn testEnum() void { expect(mem.eql(u8, os_info.Enum.fields[1].name, "Macos")); expect(os_info.Enum.fields[3].value == 3); expect(os_info.Enum.tag_type == u2); - expect(os_info.Enum.defs.len == 0); + expect(os_info.Enum.decls.len == 0); } test "type info: union info" { @@ -194,7 +194,7 @@ fn testUnion() void { expect(typeinfo_info.Union.fields[4].enum_field != null); expect(typeinfo_info.Union.fields[4].enum_field.?.value == 4); expect(typeinfo_info.Union.fields[4].field_type == @typeOf(@typeInfo(u8).Int)); - expect(typeinfo_info.Union.defs.len == 21); + expect(typeinfo_info.Union.decls.len == 21); const TestNoTagUnion = union { Foo: void, @@ -232,12 +232,12 @@ fn testStruct() void { expect(struct_info.Struct.fields.len == 3); expect(struct_info.Struct.fields[1].offset == null); expect(struct_info.Struct.fields[2].field_type == *TestStruct); - expect(struct_info.Struct.defs.len == 2); - expect(struct_info.Struct.defs[0].is_pub); - expect(!struct_info.Struct.defs[0].data.Fn.is_extern); - expect(struct_info.Struct.defs[0].data.Fn.lib_name == null); - expect(struct_info.Struct.defs[0].data.Fn.return_type == void); - expect(struct_info.Struct.defs[0].data.Fn.fn_type == fn (*const TestStruct) void); + expect(struct_info.Struct.decls.len == 2); + expect(struct_info.Struct.decls[0].is_pub); + expect(!struct_info.Struct.decls[0].data.Fn.is_extern); + expect(struct_info.Struct.decls[0].data.Fn.lib_name == null); + expect(struct_info.Struct.decls[0].data.Fn.return_type == void); + expect(struct_info.Struct.decls[0].data.Fn.fn_type == fn (*const TestStruct) void); } const TestStruct = packed struct { -- cgit v1.2.3 From 78f32259daa79aaced1c49bcdace936121a2ccc5 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 30 May 2019 15:35:30 -0400 Subject: default struct field initialization expressions closes #485 --- doc/langref.html.in | 22 ++++++++++++++++++++++ src/all_types.hpp | 1 + src/analyze.cpp | 8 +------- src/analyze.hpp | 1 + src/ir.cpp | 35 +++++++++++++++++++++++++++++++---- test/compile_errors.zig | 27 +++++++++++++++------------ test/stage1/behavior/struct.zig | 18 ++++++++++++++++++ 7 files changed, 89 insertions(+), 23 deletions(-) (limited to 'src/ir.cpp') diff --git a/doc/langref.html.in b/doc/langref.html.in index 68f3926839..622a3aeb60 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -2263,6 +2263,28 @@ test "linked list" { } {#code_end#} + {#header_open|Default Field Values#} +

+ Each struct field may have an expression indicating the default field value. Such expressions + are executed at {#link|comptime#}, and allow the field to be omitted in a struct literal expression: +

+ {#code_begin|test#} +const Foo = struct { + a: i32 = 1234, + b: i32, +}; + +test "default struct initialization fields" { + const x = Foo{ + .b = 5, + }; + if (x.a + x.b != 1239) { + @compileError("it's even comptime known!"); + } +} + {#code_end#} + {#header_close#} + {#header_open|extern struct#}

An {#syntax#}extern struct{#endsyntax#} has in-memory layout guaranteed to match the C ABI for the target.

diff --git a/src/all_types.hpp b/src/all_types.hpp index 4bb76ff64f..2a6bb1feb5 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1069,6 +1069,7 @@ struct TypeStructField { size_t gen_index; size_t offset; // byte offset from beginning of struct AstNode *decl_node; + ConstExprValue *init_val; // null and then memoized uint32_t bit_offset_in_host; // offset from the memory at gen_index uint32_t host_int_bytes; // size of host integer }; diff --git a/src/analyze.cpp b/src/analyze.cpp index 3769ae47c2..a62c24460e 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -965,9 +965,7 @@ ZigType *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind return entry; } -static ConstExprValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry, - Buf *type_name) -{ +ConstExprValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry, Buf *type_name) { size_t backward_branch_count = 0; size_t backward_branch_quota = default_backward_branch_quota; return ir_eval_const_value(g, scope, node, type_entry, @@ -2189,10 +2187,6 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) { type_struct_field->src_index = i; type_struct_field->gen_index = SIZE_MAX; - if (field_node->data.struct_field.value != nullptr) { - add_node_error(g, field_node->data.struct_field.value, - buf_sprintf("enums, not structs, support field assignment")); - } if (field_type->id == ZigTypeIdOpaque) { add_node_error(g, field_node->data.struct_field.type, buf_sprintf("opaque types have unknown size and therefore cannot be directly embedded in structs")); diff --git a/src/analyze.hpp b/src/analyze.hpp index d89bb91126..57f1072355 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -251,5 +251,6 @@ void add_cc_args(CodeGen *g, ZigList &args, const char *out_dep_pa void src_assert(bool ok, AstNode *source_node); bool is_container(ZigType *type_entry); +ConstExprValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry, Buf *type_name); #endif diff --git a/src/ir.cpp b/src/ir.cpp index c4c3808545..fb9e7b51c7 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -17887,10 +17887,37 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc bool any_missing = false; for (size_t i = 0; i < actual_field_count; i += 1) { - if (!field_assign_nodes[i]) { - ir_add_error_node(ira, instruction->source_node, - buf_sprintf("missing field: '%s'", buf_ptr(container_type->data.structure.fields[i].name))); - any_missing = true; + if (field_assign_nodes[i]) continue; + + // look for a default field value + TypeStructField *field = &container_type->data.structure.fields[i]; + if (field->init_val == nullptr) { + // it's not memoized. time to go analyze it + assert(field->decl_node->type == NodeTypeStructField); + AstNode *init_node = field->decl_node->data.struct_field.value; + if (init_node == nullptr) { + ir_add_error_node(ira, instruction->source_node, + buf_sprintf("missing field: '%s'", buf_ptr(container_type->data.structure.fields[i].name))); + any_missing = true; + continue; + } + // scope is not the scope of the struct init, it's the scope of the struct type decl + Scope *analyze_scope = &get_container_scope(container_type)->base; + // memoize it + field->init_val = analyze_const_value(ira->codegen, analyze_scope, init_node, + field->type_entry, nullptr); + } + if (type_is_invalid(field->init_val->type)) + return ira->codegen->invalid_instruction; + + IrInstruction *runtime_inst = ir_const(ira, instruction, field->init_val->type); + copy_const_val(&runtime_inst->value, field->init_val, true); + + new_fields[i].value = runtime_inst; + new_fields[i].type_struct_field = field; + + if (const_val.special == ConstValSpecialStatic) { + copy_const_val(&const_val.data.x_struct.fields[i], field->init_val, true); } } if (any_missing) diff --git a/test/compile_errors.zig b/test/compile_errors.zig index fbecacb94b..7ee5896568 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -2,6 +2,21 @@ const tests = @import("tests.zig"); const builtin = @import("builtin"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.add( + "compile error in struct init expression", + \\const Foo = struct { + \\ a: i32 = crap, + \\ b: i32, + \\}; + \\export fn entry() void { + \\ var x = Foo{ + \\ .b = 5, + \\ }; + \\} + , + "tmp.zig:2:14: error: use of undeclared identifier 'crap'", + ); + cases.add( "undefined as field type is rejected", \\const Foo = struct { @@ -5484,18 +5499,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:10:31: error: expected type 'u2', found 'u3'", ); - cases.add( - "struct fields with value assignments", - \\const MultipleChoice = struct { - \\ A: i32 = 20, - \\}; - \\export fn entry() void { - \\ var x: MultipleChoice = undefined; - \\} - , - "tmp.zig:2:14: error: enums, not structs, support field assignment", - ); - cases.add( "union fields with value assignments", \\const MultipleChoice = union { diff --git a/test/stage1/behavior/struct.zig b/test/stage1/behavior/struct.zig index 7a84fcc763..3c1db4989c 100644 --- a/test/stage1/behavior/struct.zig +++ b/test/stage1/behavior/struct.zig @@ -560,3 +560,21 @@ test "use within struct scope" { }; expectEqual(i32(42), S.inner()); } + +test "default struct initialization fields" { + const S = struct { + a: i32 = 1234, + b: i32, + }; + const x = S{ + .b = 5, + }; + if (x.a + x.b != 1239) { + @compileError("it should be comptime known"); + } + var five: i32 = 5; + const y = S{ + .b = five, + }; + expectEqual(1239, x.a + x.b); +} -- cgit v1.2.3