diff --git a/src/all_types.hpp b/src/all_types.hpp index 89c277914..6613b6e68 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -271,6 +271,7 @@ struct AstNodeErrorValueDecl { // populated by semantic analyzer TopLevelDecl top_level_decl; + ErrorTableEntry *err; }; enum BinOpType { @@ -1034,6 +1035,7 @@ struct CodeGen { HashMap primitive_type_table; HashMap unresolved_top_level_decls; HashMap fn_type_table; + HashMap error_table; uint32_t next_unresolved_index; @@ -1111,7 +1113,6 @@ struct CodeGen { LLVMValueRef trap_fn_val; bool error_during_imports; uint32_t next_node_index; - uint32_t next_error_index; uint32_t error_value_count; TypeTableEntry *err_tag_type; LLVMValueRef int_overflow_fns[2][3][4]; // [0-signed,1-unsigned][0-add,1-sub,2-mul][0-8,1-16,2-32,3-64] diff --git a/src/analyze.cpp b/src/analyze.cpp index 50fdafff7..e2b76a4a8 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -1290,36 +1290,39 @@ static void preview_fn_proto(CodeGen *g, ImportTableEntry *import, } } -static void resolve_error_value_decl(CodeGen *g, ImportTableEntry *import, AstNode *node) { +static void preview_error_value_decl(CodeGen *g, AstNode *node) { assert(node->type == NodeTypeErrorValueDecl); ErrorTableEntry *err = allocate(1); - err->value = g->next_error_index; - g->next_error_index += 1; - err->decl_node = node; buf_init_from_buf(&err->name, &node->data.error_value_decl.name); - auto existing_entry = import->block_context->error_table.maybe_get(&err->name); + auto existing_entry = g->error_table.maybe_get(&err->name); if (existing_entry) { - add_node_error(g, node, buf_sprintf("redefinition of error '%s'", buf_ptr(&err->name))); + // duplicate error definitions allowed and they get the same value + err->value = existing_entry->value->value; } else { - import->block_context->error_table.put(&err->name, err); + err->value = g->error_value_count; + g->error_value_count += 1; + g->error_table.put(&err->name, err); } + node->data.error_value_decl.err = err; +} + +static void resolve_error_value_decl(CodeGen *g, ImportTableEntry *import, AstNode *node) { + assert(node->type == NodeTypeErrorValueDecl); + + ErrorTableEntry *err = node->data.error_value_decl.err; + + import->block_context->error_table.put(&err->name, err); + bool is_pub = (node->data.error_value_decl.visib_mod != VisibModPrivate); if (is_pub) { for (int i = 0; i < import->importers.length; i += 1) { ImporterInfo importer = import->importers.at(i); - auto table_entry = importer.import->block_context->error_table.maybe_get(&err->name); - if (table_entry) { - add_node_error(g, importer.source_node, - buf_sprintf("import of error '%s' overrides existing definition", - buf_ptr(&err->name))); - } else { - importer.import->block_context->error_table.put(&err->name, err); - } + importer.import->block_context->error_table.put(&err->name, err); } } } @@ -2516,7 +2519,7 @@ static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry * add_node_error(g, node, buf_sprintf("use of undeclared error value '%s'", buf_ptr(err_name))); - return get_error_type(g, g->builtin_types.entry_void); + return g->builtin_types.entry_invalid; } @@ -2759,6 +2762,16 @@ static TypeTableEntry *analyze_bool_bin_op_expr(CodeGen *g, ImportTableEntry *im are_equal = true; } } + if (bin_op_type == BinOpTypeCmpEq) { + answer = are_equal; + } else if (bin_op_type == BinOpTypeCmpNotEq) { + answer = !are_equal; + } else { + zig_unreachable(); + } + } else if (resolved_type->id == TypeTableEntryIdPureError) { + bool are_equal = op1_val->data.x_err.err == op2_val->data.x_err.err; + if (bin_op_type == BinOpTypeCmpEq) { answer = are_equal; } else if (bin_op_type == BinOpTypeCmpNotEq) { @@ -5402,7 +5415,7 @@ void semantic_analyze(CodeGen *g) { target_import->importers.append({import, child}); } else if (child->type == NodeTypeErrorValueDecl) { - g->error_value_count += 1; + preview_error_value_decl(g, child); } } } @@ -5428,8 +5441,6 @@ void semantic_analyze(CodeGen *g) { } } - assert(g->error_value_count == g->next_error_index); - { auto it = g->import_table.entry_iterator(); for (;;) { diff --git a/src/codegen.cpp b/src/codegen.cpp index ba72aa69d..a96fe9ba0 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -28,10 +28,10 @@ CodeGen *codegen_create(Buf *root_source_dir) { g->primitive_type_table.init(32); g->unresolved_top_level_decls.init(32); g->fn_type_table.init(32); + g->error_table.init(16); g->is_release_build = false; g->is_test_build = false; g->root_source_dir = root_source_dir; - g->next_error_index = 1; g->error_value_count = 1; g->libc_lib_dir = buf_create_from_str(ZIG_LIBC_LIB_DIR); diff --git a/test/run_tests.cpp b/test/run_tests.cpp index 3f9eafcda..ef131b8ed 100644 --- a/test/run_tests.cpp +++ b/test/run_tests.cpp @@ -1789,11 +1789,6 @@ enum A {} enum A {} )SOURCE", 1, ".tmp_source.zig:3:1: error: redefinition of 'A'"); - add_compile_fail_case("redefinition of error values", R"SOURCE( -error A; -error A; - )SOURCE", 1, ".tmp_source.zig:3:1: error: redefinition of error 'A'"); - add_compile_fail_case("redefinition of global variables", R"SOURCE( var a : i32 = 1; var a : i32 = 2; diff --git a/test/self_hosted.zig b/test/self_hosted.zig index cc5fd7375..e6f9d8920 100644 --- a/test/self_hosted.zig +++ b/test/self_hosted.zig @@ -35,3 +35,14 @@ fn a_func() -> i32 { 13 } fn call_struct_field(foo: Foo) -> i32 { return foo.ptr(); } + + + +error AnError; +error AnError; +error SecondError; + +#attribute("test") +fn redefinition_of_error_values_allowed() { + if (error.AnError == error.SecondError) unreachable{} +}