diff options
| -rw-r--r-- | src/all_types.hpp | 1 | ||||
| -rw-r--r-- | src/ir.cpp | 10 | ||||
| -rw-r--r-- | src/parser.cpp | 2 | ||||
| -rw-r--r-- | test/compile_errors.zig | 22 | ||||
| -rw-r--r-- | test/tests.zig | 75 |
5 files changed, 94 insertions, 16 deletions
diff --git a/src/all_types.hpp b/src/all_types.hpp index 6fbd987b9e..f57c3124da 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -648,6 +648,7 @@ struct AstNodeFnCallExpr { ZigList<AstNode *> params; bool is_builtin; bool is_async; + bool seen; // used by @compileLog AstNode *async_allocator; }; diff --git a/src/ir.cpp b/src/ir.cpp index 0fcbb60fe8..063be4e952 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -17194,9 +17194,13 @@ static IrInstruction *ir_analyze_instruction_compile_log(IrAnalyze *ira, IrInstr } fprintf(stderr, "\n"); - // Here we bypass higher level functions such as ir_add_error because we do not want - // invalidate_exec to be called. - add_node_error(ira->codegen, instruction->base.source_node, buf_sprintf("found compile log statement")); + auto *expr = &instruction->base.source_node->data.fn_call_expr; + if (!expr->seen) { + // Here we bypass higher level functions such as ir_add_error because we do not want + // invalidate_exec to be called. + add_node_error(ira->codegen, instruction->base.source_node, buf_sprintf("found compile log statement")); + } + expr->seen = true; return ir_const_void(ira, &instruction->base); } diff --git a/src/parser.cpp b/src/parser.cpp index 3a6ce04647..6fe78c14c3 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -2739,6 +2739,7 @@ static AstNode *ast_parse_async_prefix(ParseContext *pc) { AstNode *res = ast_create_node(pc, NodeTypeFnCallExpr, async); res->data.fn_call_expr.is_async = true; + res->data.fn_call_expr.seen = false; if (eat_token_if(pc, TokenIdCmpLessThan) != nullptr) { AstNode *prefix_expr = ast_expect(pc, ast_parse_prefix_expr); expect_token(pc, TokenIdCmpGreaterThan); @@ -2759,6 +2760,7 @@ static AstNode *ast_parse_fn_call_argumnets(ParseContext *pc) { AstNode *res = ast_create_node(pc, NodeTypeFnCallExpr, paren); res->data.fn_call_expr.params = params; + res->data.fn_call_expr.seen = false; return res; } diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 9ef4af4162..a18884cc9a 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -137,6 +137,24 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { ".tmp_source.zig:3:15: error: C pointers cannot point to non-C-ABI-compatible type 'Foo'", ); + cases.addCase(x: { + var tc = cases.create( + "compile log statement warning deduplication in generic fn", + \\export fn entry() void { + \\ inner(1); + \\ inner(2); + \\} + \\fn inner(comptime n: usize) void { + \\ comptime var i = 0; + \\ inline while (i < n) : (i += 1) { @compileLog("!@#$"); } + \\} + , + ".tmp_source.zig:7:39: error: found compile log statement", + ); + tc.expect_exact = true; + break :x tc; + }); + cases.addTest( "@truncate undefined value", \\export fn entry() void { @@ -4920,7 +4938,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { cases.add( "non-printable invalid character", - "\xff\xfe" ++ + "\xff\xfe" ++ \\fn test() bool {\r \\ true\r \\} @@ -5480,7 +5498,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ Baz: void, \\}; \\comptime { - \\ var foo = Foo {.Baz = {}}; + \\ var foo = Foo {.Baz = {}}; \\ const bar_val = foo.Bar; \\} , diff --git a/test/tests.zig b/test/tests.zig index 800ddc1ccd..656c05cb9b 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -536,6 +536,7 @@ pub const CompileErrorContext = struct { name: []const u8, sources: ArrayList(SourceFile), expected_errors: ArrayList([]const u8), + expect_exact: bool, link_libc: bool, is_exe: bool, is_test: bool, @@ -565,6 +566,26 @@ pub const CompileErrorContext = struct { case: *const TestCase, build_mode: Mode, + const ErrLineIter = struct { + lines: mem.SplitIterator, + + const source_file = ".tmp_source.zig"; + + fn init(input: []const u8) ErrLineIter { + return ErrLineIter { + .lines = mem.separate(input, "\n"), + }; + } + + fn next(self: *ErrLineIter) ?[]const u8 { + while (self.lines.next()) |line| { + if (mem.indexOf(u8, line, source_file) != null) + return line; + } + return null; + } + }; + pub fn create(context: *CompileErrorContext, name: []const u8, case: *const TestCase, build_mode: Mode) *CompileCmpOutputStep { const allocator = context.b.allocator; const ptr = allocator.create(CompileCmpOutputStep) catch unreachable; @@ -674,19 +695,50 @@ pub const CompileErrorContext = struct { return error.TestFailed; } - for (self.case.expected_errors.toSliceConst()) |expected_error| { - if (mem.indexOf(u8, stderr, expected_error) == null) { - warn( - \\ - \\========= Expected this compile error: ========= - \\{} - \\================================================ - \\{} - \\ - , expected_error, stderr); - return error.TestFailed; + var ok = true; + if (self.case.expect_exact) { + var err_iter = ErrLineIter.init(stderr); + var i: usize = 0; + ok = while (err_iter.next()) |line| : (i += 1) { + if (i >= self.case.expected_errors.len) break false; + const expected = self.case.expected_errors.at(i); + if (mem.indexOf(u8, line, expected) == null) break false; + continue; + } else true; + + ok = ok and i == self.case.expected_errors.len; + + if (!ok) { + warn("\n======== Expected these compile errors: ========\n"); + for (self.case.expected_errors.toSliceConst()) |expected| { + warn("{}\n", expected); + } + } + } else { + for (self.case.expected_errors.toSliceConst()) |expected| { + if (mem.indexOf(u8, stderr, expected) == null) { + warn( + \\=========== Expected compile error: ============ + \\{} + \\ + , expected + ); + ok = false; + break; + } } } + + if (!ok) { + warn( + \\================= Full output: ================= + \\{} + \\ + , stderr + ); + return error.TestFailed; + } + warn("OK\n"); } }; @@ -704,6 +756,7 @@ pub const CompileErrorContext = struct { .name = name, .sources = ArrayList(TestCase.SourceFile).init(self.b.allocator), .expected_errors = ArrayList([]const u8).init(self.b.allocator), + .expect_exact = false, .link_libc = false, .is_exe = false, .is_test = false, |
