From 125b85d7375b96b4847f6ead51c853cdc0567506 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Wed, 23 Jun 2021 18:19:17 -0700
Subject: [PATCH 01/15] move "unreachable code" error from stage1 to stage2
* AstGen: implement "unreachable code" error for blocks. This works at
the statement level.
* stage1: remove the "unreachable code" error implementation, which
means removing the `is_gen` field from IrInstSrc. This is one small
step towards a smaller memory footprint for stage1. The benefits
won't be realized until a future commit because this flag took
advantage of padding.
There may be a regression here with "union has no associated enum"
error, and there is a regression with the following code:
```zig
const a = noreturn;
```
A future commit will address these regressions.
---
lib/std/unicode.zig | 1 -
src/AstGen.zig | 70 +++++++++++++++-------
src/stage1/all_types.hpp | 3 -
src/stage1/astgen.cpp | 121 ++++++++++++++++++---------------------
src/stage1/ir.cpp | 16 +-----
test/compile_errors.zig | 3 +-
6 files changed, 109 insertions(+), 105 deletions(-)
diff --git a/lib/std/unicode.zig b/lib/std/unicode.zig
index 0b0e470efb..78bd84ca4e 100644
--- a/lib/std/unicode.zig
+++ b/lib/std/unicode.zig
@@ -247,7 +247,6 @@ pub const Utf8View = struct {
} else |err| switch (err) {
error.InvalidUtf8 => {
@compileError("invalid utf8");
- unreachable;
},
}
}
diff --git a/src/AstGen.zig b/src/AstGen.zig
index 4254481a55..6c5f2b5dae 100644
--- a/src/AstGen.zig
+++ b/src/AstGen.zig
@@ -1570,7 +1570,7 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index) Inn
const defer_scope = scope.cast(Scope.Defer).?;
scope = defer_scope.parent;
const expr_node = node_datas[defer_scope.defer_node].rhs;
- try unusedResultExpr(parent_gz, defer_scope.parent, expr_node);
+ _ = try unusedResultExpr(parent_gz, defer_scope.parent, expr_node);
},
.defer_error => scope = scope.cast(Scope.Defer).?.parent,
.top => unreachable,
@@ -1623,7 +1623,7 @@ fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index)
const defer_scope = scope.cast(Scope.Defer).?;
scope = defer_scope.parent;
const expr_node = node_datas[defer_scope.defer_node].rhs;
- try unusedResultExpr(parent_gz, defer_scope.parent, expr_node);
+ _ = try unusedResultExpr(parent_gz, defer_scope.parent, expr_node);
},
.defer_error => scope = scope.cast(Scope.Defer).?.parent,
.namespace => break,
@@ -1785,8 +1785,23 @@ fn blockExprStmts(gz: *GenZir, parent_scope: *Scope, statements: []const ast.Nod
var block_arena = std.heap.ArenaAllocator.init(gz.astgen.gpa);
defer block_arena.deinit();
+ var noreturn_src_node: ast.Node.Index = 0;
var scope = parent_scope;
for (statements) |statement| {
+ if (noreturn_src_node != 0) {
+ return astgen.failNodeNotes(
+ statement,
+ "unreachable code",
+ .{},
+ &[_]u32{
+ try astgen.errNoteNode(
+ noreturn_src_node,
+ "control flow is diverted here",
+ .{},
+ ),
+ },
+ );
+ }
switch (node_tags[statement]) {
// zig fmt: off
.global_var_decl => scope = try varDecl(gz, scope, statement, &block_arena.allocator, tree.globalVarDecl(statement)),
@@ -1814,7 +1829,7 @@ fn blockExprStmts(gz: *GenZir, parent_scope: *Scope, statements: []const ast.Nod
.assign_mul => try assignOp(gz, scope, statement, .mul),
.assign_mul_wrap => try assignOp(gz, scope, statement, .mulwrap),
- else => try unusedResultExpr(gz, scope, statement),
+ else => noreturn_src_node = try unusedResultExpr(gz, scope, statement),
// zig fmt: on
}
}
@@ -1823,11 +1838,14 @@ fn blockExprStmts(gz: *GenZir, parent_scope: *Scope, statements: []const ast.Nod
try checkUsed(gz, parent_scope, scope);
}
-fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) InnerError!void {
+/// Returns AST source node of the thing that is noreturn if the statement is definitely `noreturn`.
+/// Otherwise returns 0.
+fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) InnerError!ast.Node.Index {
try emitDbgNode(gz, statement);
// We need to emit an error if the result is not `noreturn` or `void`, but
// we want to avoid adding the ZIR instruction if possible for performance.
const maybe_unused_result = try expr(gz, scope, .none, statement);
+ var noreturn_src_node: ast.Node.Index = 0;
const elide_check = if (gz.refToIndex(maybe_unused_result)) |inst| b: {
// Note that this array becomes invalid after appending more items to it
// in the above while loop.
@@ -2061,15 +2079,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner
.extended,
=> break :b false,
- // ZIR instructions that are always either `noreturn` or `void`.
- .breakpoint,
- .fence,
- .dbg_stmt,
- .ensure_result_used,
- .ensure_result_non_error,
- .@"export",
- .set_eval_branch_quota,
- .ensure_err_payload_void,
+ // ZIR instructions that are always `noreturn`.
.@"break",
.break_inline,
.condbr,
@@ -2078,16 +2088,30 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner
.ret_node,
.ret_coerce,
.@"unreachable",
+ .repeat,
+ .repeat_inline,
+ .panic,
+ => {
+ noreturn_src_node = statement;
+ break :b true;
+ },
+
+ // ZIR instructions that are always `void`.
+ .breakpoint,
+ .fence,
+ .dbg_stmt,
+ .ensure_result_used,
+ .ensure_result_non_error,
+ .@"export",
+ .set_eval_branch_quota,
+ .ensure_err_payload_void,
.store,
.store_node,
.store_to_block_ptr,
.store_to_inferred_ptr,
.resolve_inferred_alloc,
- .repeat,
- .repeat_inline,
.validate_struct_init_ptr,
.validate_array_init_ptr,
- .panic,
.set_align_stack,
.set_cold,
.set_float_mode,
@@ -2097,15 +2121,19 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner
} else switch (maybe_unused_result) {
.none => unreachable,
- .void_value,
- .unreachable_value,
- => true,
+ .unreachable_value => b: {
+ noreturn_src_node = statement;
+ break :b true;
+ },
+
+ .void_value => true,
else => false,
};
if (!elide_check) {
_ = try gz.addUnNode(.ensure_result_used, maybe_unused_result, statement);
}
+ return noreturn_src_node;
}
fn genDefers(
@@ -2132,7 +2160,7 @@ fn genDefers(
const prev_in_defer = gz.in_defer;
gz.in_defer = true;
defer gz.in_defer = prev_in_defer;
- try unusedResultExpr(gz, defer_scope.parent, expr_node);
+ _ = try unusedResultExpr(gz, defer_scope.parent, expr_node);
},
.defer_error => {
const defer_scope = scope.cast(Scope.Defer).?;
@@ -2142,7 +2170,7 @@ fn genDefers(
const prev_in_defer = gz.in_defer;
gz.in_defer = true;
defer gz.in_defer = prev_in_defer;
- try unusedResultExpr(gz, defer_scope.parent, expr_node);
+ _ = try unusedResultExpr(gz, defer_scope.parent, expr_node);
},
.namespace => unreachable,
.top => unreachable,
diff --git a/src/stage1/all_types.hpp b/src/stage1/all_types.hpp
index 34cd773abe..a05230058c 100644
--- a/src/stage1/all_types.hpp
+++ b/src/stage1/all_types.hpp
@@ -2733,9 +2733,6 @@ struct IrInstSrc {
IrInst base;
IrInstSrcId id;
- // true if this instruction was generated by zig and not from user code
- // this matters for the "unreachable code" compile error
- bool is_gen;
bool is_noreturn;
// When analyzing IR, instructions that point to this instruction in the "old ir"
diff --git a/src/stage1/astgen.cpp b/src/stage1/astgen.cpp
index b69cd480c6..a208f42516 100644
--- a/src/stage1/astgen.cpp
+++ b/src/stage1/astgen.cpp
@@ -2557,7 +2557,6 @@ static IrInstSrc *ir_build_reset_result(Stage1AstGen *ag, Scope *scope, AstNode
{
IrInstSrcResetResult *instruction = ir_build_instruction(ag, scope, source_node);
instruction->result_loc = result_loc;
- instruction->base.is_gen = true;
return &instruction->base;
}
@@ -2737,7 +2736,6 @@ static IrInstSrc *ir_build_alloca_src(Stage1AstGen *ag, Scope *scope, AstNode *s
IrInstSrc *align, const char *name_hint, IrInstSrc *is_comptime)
{
IrInstSrcAlloca *instruction = ir_build_instruction(ag, scope, source_node);
- instruction->base.is_gen = true;
instruction->align = align;
instruction->name_hint = name_hint;
instruction->is_comptime = is_comptime;
@@ -2752,7 +2750,6 @@ static IrInstSrc *ir_build_end_expr(Stage1AstGen *ag, Scope *scope, AstNode *sou
IrInstSrc *value, ResultLoc *result_loc)
{
IrInstSrcEndExpr *instruction = ir_build_instruction(ag, scope, source_node);
- instruction->base.is_gen = true;
instruction->value = value;
instruction->result_loc = result_loc;
@@ -2885,11 +2882,6 @@ static void ir_count_defers(Stage1AstGen *ag, Scope *inner_scope, Scope *outer_s
}
}
-static IrInstSrc *ir_mark_gen(IrInstSrc *instruction) {
- instruction->is_gen = true;
- return instruction;
-}
-
static bool astgen_defers_for_block(Stage1AstGen *ag, Scope *inner_scope, Scope *outer_scope, bool *is_noreturn, IrInstSrc *err_value) {
Scope *scope = inner_scope;
if (is_noreturn != nullptr) *is_noreturn = false;
@@ -2948,8 +2940,8 @@ static bool astgen_defers_for_block(Stage1AstGen *ag, Scope *inner_scope, Scope
if (defer_expr_value->is_noreturn) {
if (is_noreturn != nullptr) *is_noreturn = true;
} else {
- ir_mark_gen(ir_build_check_statement_is_void(ag, defer_expr_scope, defer_expr_node,
- defer_expr_value));
+ ir_build_check_statement_is_void(ag, defer_expr_scope, defer_expr_node,
+ defer_expr_value);
}
scope = scope->parent;
continue;
@@ -3047,7 +3039,7 @@ static IrInstSrc *astgen_return(Stage1AstGen *ag, Scope *scope, AstNode *node, L
ir_build_end_expr(ag, scope, node, return_value, &result_loc_ret->base);
}
- ir_mark_gen(ir_build_add_implicit_return_type(ag, scope, node, return_value, result_loc_ret));
+ ir_build_add_implicit_return_type(ag, scope, node, return_value, result_loc_ret);
size_t defer_counts[2];
ir_count_defers(ag, scope, outer_scope, defer_counts);
@@ -3074,7 +3066,7 @@ static IrInstSrc *astgen_return(Stage1AstGen *ag, Scope *scope, AstNode *node, L
is_comptime = ir_build_test_comptime(ag, scope, node, is_err);
}
- ir_mark_gen(ir_build_cond_br(ag, scope, node, is_err, err_block, ok_block, is_comptime));
+ ir_build_cond_br(ag, scope, node, is_err, err_block, ok_block, is_comptime);
Stage1ZirBasicBlock *ret_stmt_block = ir_create_basic_block(ag, scope, "RetStmt");
ir_set_cursor_at_end_and_append_block(ag, err_block);
@@ -3112,12 +3104,12 @@ static IrInstSrc *astgen_return(Stage1AstGen *ag, Scope *scope, AstNode *node, L
} else {
is_comptime = ir_build_test_comptime(ag, scope, node, is_err_val);
}
- ir_mark_gen(ir_build_cond_br(ag, scope, node, is_err_val, return_block, continue_block, is_comptime));
+ ir_build_cond_br(ag, scope, node, is_err_val, return_block, continue_block, is_comptime);
ir_set_cursor_at_end_and_append_block(ag, return_block);
IrInstSrc *err_val_ptr = ir_build_unwrap_err_code_src(ag, scope, node, err_union_ptr);
IrInstSrc *err_val = ir_build_load_ptr(ag, scope, node, err_val_ptr);
- ir_mark_gen(ir_build_add_implicit_return_type(ag, scope, node, err_val, nullptr));
+ ir_build_add_implicit_return_type(ag, scope, node, err_val, nullptr);
IrInstSrcSpillBegin *spill_begin = ir_build_spill_begin_src(ag, scope, node, err_val,
SpillIdRetErrCode);
ResultLocReturn *result_loc_ret = heap::c_allocator.create();
@@ -3338,7 +3330,7 @@ static IrInstSrc *astgen_block(Stage1AstGen *ag, Scope *parent_scope, AstNode *b
child_scope = decl_var_instruction->var->child_scope;
} else if (!is_continuation_unreachable) {
// this statement's value must be void
- ir_mark_gen(ir_build_check_statement_is_void(ag, child_scope, statement_node, statement_value));
+ ir_build_check_statement_is_void(ag, child_scope, statement_node, statement_value);
}
}
@@ -3364,7 +3356,7 @@ static IrInstSrc *astgen_block(Stage1AstGen *ag, Scope *parent_scope, AstNode *b
return ir_expr_wrap(ag, parent_scope, phi, result_loc);
} else {
incoming_blocks.append(ag->current_basic_block);
- IrInstSrc *else_expr_result = ir_mark_gen(ir_build_const_void(ag, parent_scope, block_node));
+ IrInstSrc *else_expr_result = ir_build_const_void(ag, parent_scope, block_node);
if (scope_block->peer_parent != nullptr) {
ResultLocPeer *peer_result = create_peer_result(scope_block->peer_parent);
@@ -3387,13 +3379,13 @@ static IrInstSrc *astgen_block(Stage1AstGen *ag, Scope *parent_scope, AstNode *b
IrInstSrc *result;
if (block_node->data.block.name != nullptr) {
- ir_mark_gen(ir_build_br(ag, parent_scope, block_node, scope_block->end_block, scope_block->is_comptime));
+ ir_build_br(ag, parent_scope, block_node, scope_block->end_block, scope_block->is_comptime);
ir_set_cursor_at_end_and_append_block(ag, scope_block->end_block);
IrInstSrc *phi = ir_build_phi(ag, parent_scope, block_node, incoming_blocks.length,
incoming_blocks.items, incoming_values.items, scope_block->peer_parent);
result = ir_expr_wrap(ag, parent_scope, phi, result_loc);
} else {
- IrInstSrc *void_inst = ir_mark_gen(ir_build_const_void(ag, child_scope, block_node));
+ IrInstSrc *void_inst = ir_build_const_void(ag, child_scope, block_node);
result = ir_lval_wrap(ag, parent_scope, void_inst, lval, result_loc);
}
if (!is_return_from_fn)
@@ -3402,14 +3394,14 @@ static IrInstSrc *astgen_block(Stage1AstGen *ag, Scope *parent_scope, AstNode *b
// no need for save_err_ret_addr because this cannot return error
// only generate unconditional defers
- ir_mark_gen(ir_build_add_implicit_return_type(ag, child_scope, block_node, result, nullptr));
+ ir_build_add_implicit_return_type(ag, child_scope, block_node, result, nullptr);
ResultLocReturn *result_loc_ret = heap::c_allocator.create();
result_loc_ret->base.id = ResultLocIdReturn;
ir_build_reset_result(ag, parent_scope, block_node, &result_loc_ret->base);
- ir_mark_gen(ir_build_end_expr(ag, parent_scope, block_node, result, &result_loc_ret->base));
+ ir_build_end_expr(ag, parent_scope, block_node, result, &result_loc_ret->base);
if (!astgen_defers_for_block(ag, child_scope, outer_block_scope, nullptr, nullptr))
return ag->codegen->invalid_inst_src;
- return ir_mark_gen(ir_build_return_src(ag, child_scope, result->base.source_node, result));
+ return ir_build_return_src(ag, child_scope, result->base.source_node, result);
}
static IrInstSrc *astgen_bin_op_id(Stage1AstGen *ag, Scope *scope, AstNode *node, IrBinOp op_id) {
@@ -3628,7 +3620,7 @@ static IrInstSrc *astgen_orelse(Stage1AstGen *ag, Scope *parent_scope, AstNode *
return ag->codegen->invalid_inst_src;
Stage1ZirBasicBlock *after_null_block = ag->current_basic_block;
if (!instr_is_unreachable(null_result))
- ir_mark_gen(ir_build_br(ag, parent_scope, node, end_block, is_comptime));
+ ir_build_br(ag, parent_scope, node, end_block, is_comptime);
ir_set_cursor_at_end_and_append_block(ag, ok_block);
IrInstSrc *unwrapped_ptr = ir_build_optional_unwrap_ptr(ag, parent_scope, node, maybe_ptr, false);
@@ -5395,7 +5387,7 @@ static IrInstSrc *astgen_if_bool_expr(Stage1AstGen *ag, Scope *scope, AstNode *n
return ag->codegen->invalid_inst_src;
Stage1ZirBasicBlock *after_then_block = ag->current_basic_block;
if (!instr_is_unreachable(then_expr_result))
- ir_mark_gen(ir_build_br(ag, scope, node, endif_block, is_comptime));
+ ir_build_br(ag, scope, node, endif_block, is_comptime);
ir_set_cursor_at_end_and_append_block(ag, else_block);
IrInstSrc *else_expr_result;
@@ -5409,7 +5401,7 @@ static IrInstSrc *astgen_if_bool_expr(Stage1AstGen *ag, Scope *scope, AstNode *n
}
Stage1ZirBasicBlock *after_else_block = ag->current_basic_block;
if (!instr_is_unreachable(else_expr_result))
- ir_mark_gen(ir_build_br(ag, scope, node, endif_block, is_comptime));
+ ir_build_br(ag, scope, node, endif_block, is_comptime);
ir_set_cursor_at_end_and_append_block(ag, endif_block);
IrInstSrc **incoming_values = heap::c_allocator.allocate(2);
@@ -5954,12 +5946,11 @@ static IrInstSrc *astgen_while_expr(Stage1AstGen *ag, Scope *scope, AstNode *nod
IrInstSrc *is_err = ir_build_test_err_src(ag, scope, node->data.while_expr.condition, err_val_ptr,
true, false);
Stage1ZirBasicBlock *after_cond_block = ag->current_basic_block;
- IrInstSrc *void_else_result = else_node ? nullptr : ir_mark_gen(ir_build_const_void(ag, scope, node));
+ IrInstSrc *void_else_result = else_node ? nullptr : ir_build_const_void(ag, scope, node);
IrInstSrc *cond_br_inst;
if (!instr_is_unreachable(is_err)) {
cond_br_inst = ir_build_cond_br(ag, scope, node->data.while_expr.condition, is_err,
else_block, body_block, is_comptime);
- cond_br_inst->is_gen = true;
} else {
// for the purposes of the source instruction to ir_build_result_peers
cond_br_inst = ag->current_basic_block->instruction_list.last();
@@ -6005,8 +5996,8 @@ static IrInstSrc *astgen_while_expr(Stage1AstGen *ag, Scope *scope, AstNode *nod
}
if (!instr_is_unreachable(body_result)) {
- ir_mark_gen(ir_build_check_statement_is_void(ag, payload_scope, node->data.while_expr.body, body_result));
- ir_mark_gen(ir_build_br(ag, payload_scope, node, continue_block, is_comptime));
+ ir_build_check_statement_is_void(ag, payload_scope, node->data.while_expr.body, body_result);
+ ir_build_br(ag, payload_scope, node, continue_block, is_comptime);
}
if (continue_expr_node) {
@@ -6015,8 +6006,8 @@ static IrInstSrc *astgen_while_expr(Stage1AstGen *ag, Scope *scope, AstNode *nod
if (expr_result == ag->codegen->invalid_inst_src)
return expr_result;
if (!instr_is_unreachable(expr_result)) {
- ir_mark_gen(ir_build_check_statement_is_void(ag, payload_scope, continue_expr_node, expr_result));
- ir_mark_gen(ir_build_br(ag, payload_scope, node, cond_block, is_comptime));
+ ir_build_check_statement_is_void(ag, payload_scope, continue_expr_node, expr_result);
+ ir_build_br(ag, payload_scope, node, cond_block, is_comptime);
}
}
@@ -6041,7 +6032,7 @@ static IrInstSrc *astgen_while_expr(Stage1AstGen *ag, Scope *scope, AstNode *nod
if (else_result == ag->codegen->invalid_inst_src)
return else_result;
if (!instr_is_unreachable(else_result))
- ir_mark_gen(ir_build_br(ag, scope, node, end_block, is_comptime));
+ ir_build_br(ag, scope, node, end_block, is_comptime);
Stage1ZirBasicBlock *after_else_block = ag->current_basic_block;
ir_set_cursor_at_end_and_append_block(ag, end_block);
if (else_result) {
@@ -6075,12 +6066,11 @@ static IrInstSrc *astgen_while_expr(Stage1AstGen *ag, Scope *scope, AstNode *nod
IrInstSrc *maybe_val = ir_build_load_ptr(ag, scope, node->data.while_expr.condition, maybe_val_ptr);
IrInstSrc *is_non_null = ir_build_test_non_null_src(ag, scope, node->data.while_expr.condition, maybe_val);
Stage1ZirBasicBlock *after_cond_block = ag->current_basic_block;
- IrInstSrc *void_else_result = else_node ? nullptr : ir_mark_gen(ir_build_const_void(ag, scope, node));
+ IrInstSrc *void_else_result = else_node ? nullptr : ir_build_const_void(ag, scope, node);
IrInstSrc *cond_br_inst;
if (!instr_is_unreachable(is_non_null)) {
cond_br_inst = ir_build_cond_br(ag, scope, node->data.while_expr.condition, is_non_null,
body_block, else_block, is_comptime);
- cond_br_inst->is_gen = true;
} else {
// for the purposes of the source instruction to ir_build_result_peers
cond_br_inst = ag->current_basic_block->instruction_list.last();
@@ -6123,8 +6113,8 @@ static IrInstSrc *astgen_while_expr(Stage1AstGen *ag, Scope *scope, AstNode *nod
}
if (!instr_is_unreachable(body_result)) {
- ir_mark_gen(ir_build_check_statement_is_void(ag, child_scope, node->data.while_expr.body, body_result));
- ir_mark_gen(ir_build_br(ag, child_scope, node, continue_block, is_comptime));
+ ir_build_check_statement_is_void(ag, child_scope, node->data.while_expr.body, body_result);
+ ir_build_br(ag, child_scope, node, continue_block, is_comptime);
}
if (continue_expr_node) {
@@ -6133,8 +6123,8 @@ static IrInstSrc *astgen_while_expr(Stage1AstGen *ag, Scope *scope, AstNode *nod
if (expr_result == ag->codegen->invalid_inst_src)
return expr_result;
if (!instr_is_unreachable(expr_result)) {
- ir_mark_gen(ir_build_check_statement_is_void(ag, child_scope, continue_expr_node, expr_result));
- ir_mark_gen(ir_build_br(ag, child_scope, node, cond_block, is_comptime));
+ ir_build_check_statement_is_void(ag, child_scope, continue_expr_node, expr_result);
+ ir_build_br(ag, child_scope, node, cond_block, is_comptime);
}
}
@@ -6151,7 +6141,7 @@ static IrInstSrc *astgen_while_expr(Stage1AstGen *ag, Scope *scope, AstNode *nod
if (else_result == ag->codegen->invalid_inst_src)
return else_result;
if (!instr_is_unreachable(else_result))
- ir_mark_gen(ir_build_br(ag, scope, node, end_block, is_comptime));
+ ir_build_br(ag, scope, node, end_block, is_comptime);
}
Stage1ZirBasicBlock *after_else_block = ag->current_basic_block;
ir_set_cursor_at_end_and_append_block(ag, end_block);
@@ -6175,12 +6165,11 @@ static IrInstSrc *astgen_while_expr(Stage1AstGen *ag, Scope *scope, AstNode *nod
if (cond_val == ag->codegen->invalid_inst_src)
return cond_val;
Stage1ZirBasicBlock *after_cond_block = ag->current_basic_block;
- IrInstSrc *void_else_result = else_node ? nullptr : ir_mark_gen(ir_build_const_void(ag, scope, node));
+ IrInstSrc *void_else_result = else_node ? nullptr : ir_build_const_void(ag, scope, node);
IrInstSrc *cond_br_inst;
if (!instr_is_unreachable(cond_val)) {
cond_br_inst = ir_build_cond_br(ag, scope, node->data.while_expr.condition, cond_val,
body_block, else_block, is_comptime);
- cond_br_inst->is_gen = true;
} else {
// for the purposes of the source instruction to ir_build_result_peers
cond_br_inst = ag->current_basic_block->instruction_list.last();
@@ -6219,8 +6208,8 @@ static IrInstSrc *astgen_while_expr(Stage1AstGen *ag, Scope *scope, AstNode *nod
}
if (!instr_is_unreachable(body_result)) {
- ir_mark_gen(ir_build_check_statement_is_void(ag, scope, node->data.while_expr.body, body_result));
- ir_mark_gen(ir_build_br(ag, scope, node, continue_block, is_comptime));
+ ir_build_check_statement_is_void(ag, scope, node->data.while_expr.body, body_result);
+ ir_build_br(ag, scope, node, continue_block, is_comptime);
}
if (continue_expr_node) {
@@ -6229,8 +6218,8 @@ static IrInstSrc *astgen_while_expr(Stage1AstGen *ag, Scope *scope, AstNode *nod
if (expr_result == ag->codegen->invalid_inst_src)
return expr_result;
if (!instr_is_unreachable(expr_result)) {
- ir_mark_gen(ir_build_check_statement_is_void(ag, scope, continue_expr_node, expr_result));
- ir_mark_gen(ir_build_br(ag, scope, node, cond_block, is_comptime));
+ ir_build_check_statement_is_void(ag, scope, continue_expr_node, expr_result);
+ ir_build_br(ag, scope, node, cond_block, is_comptime);
}
}
@@ -6248,7 +6237,7 @@ static IrInstSrc *astgen_while_expr(Stage1AstGen *ag, Scope *scope, AstNode *nod
if (else_result == ag->codegen->invalid_inst_src)
return else_result;
if (!instr_is_unreachable(else_result))
- ir_mark_gen(ir_build_br(ag, scope, node, end_block, is_comptime));
+ ir_build_br(ag, scope, node, end_block, is_comptime);
}
Stage1ZirBasicBlock *after_else_block = ag->current_basic_block;
ir_set_cursor_at_end_and_append_block(ag, end_block);
@@ -6332,9 +6321,9 @@ static IrInstSrc *astgen_for_expr(Stage1AstGen *ag, Scope *parent_scope, AstNode
IrInstSrc *index_val = ir_build_load_ptr(ag, &spill_scope->base, node, index_ptr);
IrInstSrc *cond = ir_build_bin_op(ag, parent_scope, node, IrBinOpCmpLessThan, index_val, len_val, false);
Stage1ZirBasicBlock *after_cond_block = ag->current_basic_block;
- IrInstSrc *void_else_value = else_node ? nullptr : ir_mark_gen(ir_build_const_void(ag, parent_scope, node));
- IrInstSrc *cond_br_inst = ir_mark_gen(ir_build_cond_br(ag, parent_scope, node, cond,
- body_block, else_block, is_comptime));
+ IrInstSrc *void_else_value = else_node ? nullptr : ir_build_const_void(ag, parent_scope, node);
+ IrInstSrc *cond_br_inst = ir_build_cond_br(ag, parent_scope, node, cond,
+ body_block, else_block, is_comptime);
ResultLocPeerParent *peer_parent = ir_build_result_peers(ag, cond_br_inst, end_block, result_loc, is_comptime);
@@ -6377,8 +6366,8 @@ static IrInstSrc *astgen_for_expr(Stage1AstGen *ag, Scope *parent_scope, AstNode
}
if (!instr_is_unreachable(body_result)) {
- ir_mark_gen(ir_build_check_statement_is_void(ag, child_scope, node->data.for_expr.body, body_result));
- ir_mark_gen(ir_build_br(ag, child_scope, node, continue_block, is_comptime));
+ ir_build_check_statement_is_void(ag, child_scope, node->data.for_expr.body, body_result);
+ ir_build_br(ag, child_scope, node, continue_block, is_comptime);
}
ir_set_cursor_at_end_and_append_block(ag, continue_block);
@@ -6399,7 +6388,7 @@ static IrInstSrc *astgen_for_expr(Stage1AstGen *ag, Scope *parent_scope, AstNode
if (else_result == ag->codegen->invalid_inst_src)
return else_result;
if (!instr_is_unreachable(else_result))
- ir_mark_gen(ir_build_br(ag, parent_scope, node, end_block, is_comptime));
+ ir_build_br(ag, parent_scope, node, end_block, is_comptime);
}
Stage1ZirBasicBlock *after_else_block = ag->current_basic_block;
ir_set_cursor_at_end_and_append_block(ag, end_block);
@@ -6719,7 +6708,7 @@ static IrInstSrc *astgen_if_optional_expr(Stage1AstGen *ag, Scope *scope, AstNod
return then_expr_result;
Stage1ZirBasicBlock *after_then_block = ag->current_basic_block;
if (!instr_is_unreachable(then_expr_result))
- ir_mark_gen(ir_build_br(ag, scope, node, endif_block, is_comptime));
+ ir_build_br(ag, scope, node, endif_block, is_comptime);
ir_set_cursor_at_end_and_append_block(ag, else_block);
IrInstSrc *else_expr_result;
@@ -6733,7 +6722,7 @@ static IrInstSrc *astgen_if_optional_expr(Stage1AstGen *ag, Scope *scope, AstNod
}
Stage1ZirBasicBlock *after_else_block = ag->current_basic_block;
if (!instr_is_unreachable(else_expr_result))
- ir_mark_gen(ir_build_br(ag, scope, node, endif_block, is_comptime));
+ ir_build_br(ag, scope, node, endif_block, is_comptime);
ir_set_cursor_at_end_and_append_block(ag, endif_block);
IrInstSrc **incoming_values = heap::c_allocator.allocate(2);
@@ -6802,7 +6791,7 @@ static IrInstSrc *astgen_if_err_expr(Stage1AstGen *ag, Scope *scope, AstNode *no
return then_expr_result;
Stage1ZirBasicBlock *after_then_block = ag->current_basic_block;
if (!instr_is_unreachable(then_expr_result))
- ir_mark_gen(ir_build_br(ag, scope, node, endif_block, is_comptime));
+ ir_build_br(ag, scope, node, endif_block, is_comptime);
ir_set_cursor_at_end_and_append_block(ag, else_block);
@@ -6831,7 +6820,7 @@ static IrInstSrc *astgen_if_err_expr(Stage1AstGen *ag, Scope *scope, AstNode *no
}
Stage1ZirBasicBlock *after_else_block = ag->current_basic_block;
if (!instr_is_unreachable(else_expr_result))
- ir_mark_gen(ir_build_br(ag, scope, node, endif_block, is_comptime));
+ ir_build_br(ag, scope, node, endif_block, is_comptime);
ir_set_cursor_at_end_and_append_block(ag, endif_block);
IrInstSrc **incoming_values = heap::c_allocator.allocate(2);
@@ -6893,7 +6882,7 @@ static bool astgen_switch_prong_expr(Stage1AstGen *ag, Scope *scope, AstNode *sw
if (expr_result == ag->codegen->invalid_inst_src)
return false;
if (!instr_is_unreachable(expr_result))
- ir_mark_gen(ir_build_br(ag, scope, switch_node, end_block, is_comptime));
+ ir_build_br(ag, scope, switch_node, end_block, is_comptime);
incoming_blocks->append(ag->current_basic_block);
incoming_values->append(expr_result);
return true;
@@ -7008,8 +6997,8 @@ static IrInstSrc *astgen_switch_expr(Stage1AstGen *ag, Scope *scope, AstNode *no
assert(ok_bit);
assert(last_item_node);
- IrInstSrc *br_inst = ir_mark_gen(ir_build_cond_br(ag, scope, last_item_node, ok_bit,
- range_block_yes, range_block_no, is_comptime));
+ IrInstSrc *br_inst = ir_build_cond_br(ag, scope, last_item_node, ok_bit,
+ range_block_yes, range_block_no, is_comptime);
if (peer_parent->base.source_instruction == nullptr) {
peer_parent->base.source_instruction = br_inst;
}
@@ -7349,14 +7338,14 @@ static IrInstSrc *astgen_continue(Stage1AstGen *ag, Scope *continue_scope, AstNo
for (size_t i = 0; i < runtime_scopes.length; i += 1) {
ScopeRuntime *scope_runtime = runtime_scopes.at(i);
- ir_mark_gen(ir_build_check_runtime_scope(ag, continue_scope, node, scope_runtime->is_comptime, is_comptime));
+ ir_build_check_runtime_scope(ag, continue_scope, node, scope_runtime->is_comptime, is_comptime);
}
runtime_scopes.deinit();
Stage1ZirBasicBlock *dest_block = loop_scope->continue_block;
if (!astgen_defers_for_block(ag, continue_scope, dest_block->scope, nullptr, nullptr))
return ag->codegen->invalid_inst_src;
- return ir_mark_gen(ir_build_br(ag, continue_scope, node, dest_block, is_comptime));
+ return ir_build_br(ag, continue_scope, node, dest_block, is_comptime);
}
static IrInstSrc *astgen_error_type(Stage1AstGen *ag, Scope *scope, AstNode *node) {
@@ -7482,7 +7471,7 @@ static IrInstSrc *astgen_catch(Stage1AstGen *ag, Scope *parent_scope, AstNode *n
return ag->codegen->invalid_inst_src;
Stage1ZirBasicBlock *after_err_block = ag->current_basic_block;
if (!instr_is_unreachable(err_result))
- ir_mark_gen(ir_build_br(ag, parent_scope, node, end_block, is_comptime));
+ ir_build_br(ag, parent_scope, node, end_block, is_comptime);
ir_set_cursor_at_end_and_append_block(ag, ok_block);
IrInstSrc *unwrapped_ptr = ir_build_unwrap_err_payload_src(ag, parent_scope, node, err_union_ptr, false, false);
@@ -7757,9 +7746,9 @@ static IrInstSrc *astgen_suspend(Stage1AstGen *ag, Scope *parent_scope, AstNode
IrInstSrc *susp_res = astgen_node(ag, node->data.suspend.block, child_scope);
if (susp_res == ag->codegen->invalid_inst_src)
return ag->codegen->invalid_inst_src;
- ir_mark_gen(ir_build_check_statement_is_void(ag, child_scope, node->data.suspend.block, susp_res));
+ ir_build_check_statement_is_void(ag, child_scope, node->data.suspend.block, susp_res);
- return ir_mark_gen(ir_build_suspend_finish_src(ag, parent_scope, node, begin));
+ return ir_build_suspend_finish_src(ag, parent_scope, node, begin);
}
static IrInstSrc *astgen_node_raw(Stage1AstGen *ag, AstNode *node, Scope *scope,
@@ -8073,13 +8062,13 @@ bool stage1_astgen(CodeGen *codegen, AstNode *node, Scope *scope, Stage1Zir *sta
}
if (!instr_is_unreachable(result)) {
- ir_mark_gen(ir_build_add_implicit_return_type(ag, scope, result->base.source_node, result, nullptr));
+ ir_build_add_implicit_return_type(ag, scope, result->base.source_node, result, nullptr);
// no need for save_err_ret_addr because this cannot return error
ResultLocReturn *result_loc_ret = heap::c_allocator.create();
result_loc_ret->base.id = ResultLocIdReturn;
ir_build_reset_result(ag, scope, node, &result_loc_ret->base);
- ir_mark_gen(ir_build_end_expr(ag, scope, node, result, &result_loc_ret->base));
- ir_mark_gen(ir_build_return_src(ag, scope, result->base.source_node, result));
+ ir_build_end_expr(ag, scope, node, result, &result_loc_ret->base);
+ ir_build_return_src(ag, scope, result->base.source_node, result);
}
return true;
diff --git a/src/stage1/ir.cpp b/src/stage1/ir.cpp
index 2200e8380d..0c915f5c35 100644
--- a/src/stage1/ir.cpp
+++ b/src/stage1/ir.cpp
@@ -5407,16 +5407,6 @@ static void ir_finish_bb(IrAnalyze *ira) {
ira->new_irb.current_basic_block->debug_id);
}
}
- ira->instruction_index += 1;
- while (ira->instruction_index < ira->zir_current_basic_block->instruction_list.length) {
- IrInstSrc *next_instruction = ira->zir_current_basic_block->instruction_list.at(ira->instruction_index);
- if (!next_instruction->is_gen) {
- ir_add_error(ira, &next_instruction->base, buf_sprintf("unreachable code"));
- break;
- }
- ira->instruction_index += 1;
- }
-
ir_start_next_bb(ira);
}
@@ -15934,7 +15924,7 @@ static IrInstGen *ir_analyze_instruction_pop_count(IrAnalyze *ira, IrInstSrcPopC
return ir_build_pop_count_gen(ira, &instruction->base.base, return_type, op);
}
-static IrInstGen *ir_analyze_union_tag(IrAnalyze *ira, IrInst* source_instr, IrInstGen *value, bool is_gen) {
+static IrInstGen *ir_analyze_union_tag(IrAnalyze *ira, IrInst* source_instr, IrInstGen *value) {
if (type_is_invalid(value->value->type))
return ira->codegen->invalid_inst_gen;
@@ -15943,7 +15933,7 @@ static IrInstGen *ir_analyze_union_tag(IrAnalyze *ira, IrInst* source_instr, IrI
buf_sprintf("expected enum or union type, found '%s'", buf_ptr(&value->value->type->name)));
return ira->codegen->invalid_inst_gen;
}
- if (!value->value->type->data.unionation.have_explicit_tag_type && !is_gen) {
+ if (!value->value->type->data.unionation.have_explicit_tag_type) {
ErrorMsg *msg = ir_add_error(ira, source_instr, buf_sprintf("union has no associated enum"));
if (value->value->type->data.unionation.decl_node != nullptr) {
add_error_note(ira->codegen, msg, value->value->type->data.unionation.decl_node,
@@ -16906,7 +16896,7 @@ static IrInstGen *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrInstSrc
}
if (target_type->id == ZigTypeIdUnion) {
- target = ir_analyze_union_tag(ira, &instruction->base.base, target, instruction->base.is_gen);
+ target = ir_analyze_union_tag(ira, &instruction->base.base, target);
if (type_is_invalid(target->value->type))
return ira->codegen->invalid_inst_gen;
target_type = target->value->type;
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
index bb7cfcfc1d..3be754377b 100644
--- a/test/compile_errors.zig
+++ b/test/compile_errors.zig
@@ -4762,7 +4762,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\fn b() void {}
, &[_][]const u8{
- "tmp.zig:3:5: error: unreachable code",
+ "tmp.zig:3:6: error: unreachable code",
+ "tmp.zig:2:5: note: control flow is diverted here",
});
cases.add("bad import",
From 527c55aa5671381a7e6652fba237279453e0bb6e Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Wed, 23 Jun 2021 18:34:01 -0700
Subject: [PATCH 02/15] stage1: get rid of the is_noreturn flag on IrInstSrc
One more step towards lowering the memory footprint of stage1. This flag
was hiding in padding but now that it is gone we can re-arrange the
memory layout more easily.
---
src/stage1/all_types.hpp | 1 -
src/stage1/astgen.cpp | 20 ++++++++++++--------
src/stage1/ir_print.cpp | 2 --
3 files changed, 12 insertions(+), 11 deletions(-)
diff --git a/src/stage1/all_types.hpp b/src/stage1/all_types.hpp
index a05230058c..939798428d 100644
--- a/src/stage1/all_types.hpp
+++ b/src/stage1/all_types.hpp
@@ -2733,7 +2733,6 @@ struct IrInstSrc {
IrInst base;
IrInstSrcId id;
- bool is_noreturn;
// When analyzing IR, instructions that point to this instruction in the "old ir"
// can find the instruction that corresponds to this value in the "new ir"
diff --git a/src/stage1/astgen.cpp b/src/stage1/astgen.cpp
index a208f42516..a95d0af9de 100644
--- a/src/stage1/astgen.cpp
+++ b/src/stage1/astgen.cpp
@@ -55,7 +55,17 @@ static ErrorMsg *exec_add_error_node(CodeGen *codegen, Stage1Zir *exec, AstNode
static bool instr_is_unreachable(IrInstSrc *instruction) {
- return instruction->is_noreturn;
+ switch (instruction->id) {
+ case IrInstSrcIdCondBr:
+ case IrInstSrcIdReturn:
+ case IrInstSrcIdBr:
+ case IrInstSrcIdUnreachable:
+ case IrInstSrcIdSwitchBr:
+ case IrInstSrcIdPanic:
+ return true;
+ default:
+ return false;
+ }
}
void destroy_instruction_src(IrInstSrc *inst) {
@@ -947,7 +957,6 @@ static IrInstSrc *ir_build_cond_br(Stage1AstGen *ag, Scope *scope, AstNode *sour
Stage1ZirBasicBlock *then_block, Stage1ZirBasicBlock *else_block, IrInstSrc *is_comptime)
{
IrInstSrcCondBr *inst = ir_build_instruction(ag, scope, source_node);
- inst->base.is_noreturn = true;
inst->condition = condition;
inst->then_block = then_block;
inst->else_block = else_block;
@@ -963,7 +972,6 @@ static IrInstSrc *ir_build_cond_br(Stage1AstGen *ag, Scope *scope, AstNode *sour
static IrInstSrc *ir_build_return_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, IrInstSrc *operand) {
IrInstSrcReturn *inst = ir_build_instruction(ag, scope, source_node);
- inst->base.is_noreturn = true;
inst->operand = operand;
if (operand != nullptr) ir_ref_instruction(operand, ag->current_basic_block);
@@ -1303,7 +1311,6 @@ static IrInstSrc *ir_build_br(Stage1AstGen *ag, Scope *scope, AstNode *source_no
Stage1ZirBasicBlock *dest_block, IrInstSrc *is_comptime)
{
IrInstSrcBr *inst = ir_build_instruction(ag, scope, source_node);
- inst->base.is_noreturn = true;
inst->dest_block = dest_block;
inst->is_comptime = is_comptime;
@@ -1418,7 +1425,6 @@ static IrInstSrc *ir_build_container_init_fields(Stage1AstGen *ag, Scope *scope,
static IrInstSrc *ir_build_unreachable(Stage1AstGen *ag, Scope *scope, AstNode *source_node) {
IrInstSrcUnreachable *inst = ir_build_instruction(ag, scope, source_node);
- inst->base.is_noreturn = true;
return &inst->base;
}
@@ -1718,7 +1724,6 @@ static IrInstSrcSwitchBr *ir_build_switch_br_src(Stage1AstGen *ag, Scope *scope,
IrInstSrc *is_comptime, IrInstSrc *switch_prongs_void)
{
IrInstSrcSwitchBr *instruction = ir_build_instruction(ag, scope, source_node);
- instruction->base.is_noreturn = true;
instruction->target_value = target_value;
instruction->else_block = else_block;
instruction->case_count = case_count;
@@ -2439,7 +2444,6 @@ static IrInstSrc *ir_build_decl_ref(Stage1AstGen *ag, Scope *scope, AstNode *sou
static IrInstSrc *ir_build_panic_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, IrInstSrc *msg) {
IrInstSrcPanic *instruction = ir_build_instruction(ag, scope, source_node);
- instruction->base.is_noreturn = true;
instruction->msg = msg;
ir_ref_instruction(msg, ag->current_basic_block);
@@ -2937,7 +2941,7 @@ static bool astgen_defers_for_block(Stage1AstGen *ag, Scope *inner_scope, Scope
if (defer_expr_value == ag->codegen->invalid_inst_src)
return ag->codegen->invalid_inst_src;
- if (defer_expr_value->is_noreturn) {
+ if (instr_is_unreachable(defer_expr_value)) {
if (is_noreturn != nullptr) *is_noreturn = true;
} else {
ir_build_check_statement_is_void(ag, defer_expr_scope, defer_expr_node,
diff --git a/src/stage1/ir_print.cpp b/src/stage1/ir_print.cpp
index c6837b21cc..11144ead72 100644
--- a/src/stage1/ir_print.cpp
+++ b/src/stage1/ir_print.cpp
@@ -577,8 +577,6 @@ static void ir_print_prefix_src(IrPrintSrc *irp, IrInstSrc *instruction, bool tr
const char *type_name;
if (instruction->id == IrInstSrcIdConst) {
type_name = buf_ptr(&reinterpret_cast(instruction)->value->type->name);
- } else if (instruction->is_noreturn) {
- type_name = "noreturn";
} else {
type_name = "(unknown)";
}
From cffa22a658d23bdedbdd7e23853b80d856e43627 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 25 Jun 2021 19:43:01 -0700
Subject: [PATCH 03/15] AstGen: implement compile error for useless locals
When a local variable has an initialization expression of type
'noreturn', emit a compile error. This brings this branch closer
to parity with master branch.
---
src/AstGen.zig | 31 ++++++++++++++++++++++++++++++-
test/compile_errors.zig | 3 ++-
2 files changed, 32 insertions(+), 2 deletions(-)
diff --git a/src/AstGen.zig b/src/AstGen.zig
index 6c5f2b5dae..c74106ef44 100644
--- a/src/AstGen.zig
+++ b/src/AstGen.zig
@@ -2332,6 +2332,8 @@ fn varDecl(
.ty = try typeExpr(gz, scope, var_decl.ast.type_node),
} else .none;
const init_inst = try expr(gz, scope, result_loc, var_decl.ast.init_node);
+ try astgen.checkVarInitExpr(gz.*, node, var_decl.ast.init_node, init_inst, "local constant");
+
const sub_scope = try block_arena.create(Scope.LocalVal);
sub_scope.* = .{
.parent = scope,
@@ -2382,6 +2384,8 @@ fn varDecl(
}
const init_result_loc: ResultLoc = .{ .block_ptr = &init_scope };
const init_inst = try expr(&init_scope, &init_scope.base, init_result_loc, var_decl.ast.init_node);
+ try astgen.checkVarInitExpr(init_scope, node, var_decl.ast.init_node, init_inst, "local constant");
+
const zir_tags = astgen.instructions.items(.tag);
const zir_datas = astgen.instructions.items(.data);
@@ -2482,7 +2486,8 @@ fn varDecl(
resolve_inferred_alloc = alloc;
break :a .{ .alloc = alloc, .result_loc = .{ .inferred_ptr = alloc } };
};
- _ = try expr(gz, scope, var_data.result_loc, var_decl.ast.init_node);
+ const init_inst = try expr(gz, scope, var_data.result_loc, var_decl.ast.init_node);
+ try astgen.checkVarInitExpr(gz.*, node, var_decl.ast.init_node, init_inst, "local variable");
if (resolve_inferred_alloc != .none) {
_ = try gz.addUnNode(.resolve_inferred_alloc, resolve_inferred_alloc, node);
}
@@ -9602,3 +9607,27 @@ fn advanceSourceCursor(astgen: *AstGen, source: []const u8, end: usize) void {
astgen.source_line = line;
astgen.source_column = column;
}
+
+fn checkVarInitExpr(
+ astgen: *AstGen,
+ gz: GenZir,
+ var_node: ast.Node.Index,
+ init_node: ast.Node.Index,
+ init_inst: Zir.Inst.Ref,
+ var_name_text: []const u8,
+) !void {
+ if (gz.refIsNoReturn(init_inst)) {
+ return astgen.failNodeNotes(
+ var_node,
+ "useless {s}",
+ .{var_name_text},
+ &[_]u32{
+ try astgen.errNoteNode(
+ init_node,
+ "control flow is diverted here",
+ .{},
+ ),
+ },
+ );
+ }
+}
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
index 3be754377b..0c04f70a86 100644
--- a/test/compile_errors.zig
+++ b/test/compile_errors.zig
@@ -4831,7 +4831,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const a = return;
\\}
, &[_][]const u8{
- "tmp.zig:2:5: error: unreachable code",
+ "tmp.zig:2:5: error: useless local constant",
+ "tmp.zig:2:15: note: control flow is diverted here",
});
cases.add("unreachable variable",
From 7f5560689aeb0e2ab84c5e3dc48f84247bd5bdc3 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Mon, 28 Jun 2021 14:16:15 -0700
Subject: [PATCH 04/15] AstGen: introduce 'reachableExpr' function
This function can be swapped out for calls to expr() to report a compile
error when the expression results in control flow that does not return.
---
src/AstGen.zig | 59 +++++++++++++++++------------------------
test/compile_errors.zig | 16 +++++++----
2 files changed, 36 insertions(+), 39 deletions(-)
diff --git a/src/AstGen.zig b/src/AstGen.zig
index c74106ef44..15b5b88d9a 100644
--- a/src/AstGen.zig
+++ b/src/AstGen.zig
@@ -261,6 +261,23 @@ fn typeExpr(gz: *GenZir, scope: *Scope, type_node: ast.Node.Index) InnerError!Zi
return expr(gz, scope, .{ .ty = .type_type }, type_node);
}
+/// Same as `expr` but fails with a compile error if the result type is `noreturn`.
+fn reachableExpr(
+ gz: *GenZir,
+ scope: *Scope,
+ rl: ResultLoc,
+ node: ast.Node.Index,
+ src_node: ast.Node.Index,
+) InnerError!Zir.Inst.Ref {
+ const result_inst = try expr(gz, scope, rl, node);
+ if (gz.refIsNoReturn(result_inst)) {
+ return gz.astgen.failNodeNotes(src_node, "unreachable code", .{}, &[_]u32{
+ try gz.astgen.errNoteNode(node, "control flow is diverted here", .{}),
+ });
+ }
+ return result_inst;
+}
+
fn lvalExpr(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref {
const astgen = gz.astgen;
const tree = astgen.tree;
@@ -2331,8 +2348,7 @@ fn varDecl(
const result_loc: ResultLoc = if (var_decl.ast.type_node != 0) .{
.ty = try typeExpr(gz, scope, var_decl.ast.type_node),
} else .none;
- const init_inst = try expr(gz, scope, result_loc, var_decl.ast.init_node);
- try astgen.checkVarInitExpr(gz.*, node, var_decl.ast.init_node, init_inst, "local constant");
+ const init_inst = try reachableExpr(gz, scope, result_loc, var_decl.ast.init_node, node);
const sub_scope = try block_arena.create(Scope.LocalVal);
sub_scope.* = .{
@@ -2383,8 +2399,7 @@ fn varDecl(
init_scope.rl_ptr = alloc;
}
const init_result_loc: ResultLoc = .{ .block_ptr = &init_scope };
- const init_inst = try expr(&init_scope, &init_scope.base, init_result_loc, var_decl.ast.init_node);
- try astgen.checkVarInitExpr(init_scope, node, var_decl.ast.init_node, init_inst, "local constant");
+ const init_inst = try reachableExpr(&init_scope, &init_scope.base, init_result_loc, var_decl.ast.init_node, node);
const zir_tags = astgen.instructions.items(.tag);
const zir_datas = astgen.instructions.items(.data);
@@ -2486,8 +2501,7 @@ fn varDecl(
resolve_inferred_alloc = alloc;
break :a .{ .alloc = alloc, .result_loc = .{ .inferred_ptr = alloc } };
};
- const init_inst = try expr(gz, scope, var_data.result_loc, var_decl.ast.init_node);
- try astgen.checkVarInitExpr(gz.*, node, var_decl.ast.init_node, init_inst, "local variable");
+ _ = try reachableExpr(gz, scope, var_data.result_loc, var_decl.ast.init_node, node);
if (resolve_inferred_alloc != .none) {
_ = try gz.addUnNode(.resolve_inferred_alloc, resolve_inferred_alloc, node);
}
@@ -6618,14 +6632,14 @@ fn as(
const dest_type = try typeExpr(gz, scope, lhs);
switch (rl) {
.none, .none_or_ref, .discard, .ref, .ty => {
- const result = try expr(gz, scope, .{ .ty = dest_type }, rhs);
+ const result = try reachableExpr(gz, scope, .{ .ty = dest_type }, rhs, node);
return rvalue(gz, rl, result, node);
},
.ptr, .inferred_ptr => |result_ptr| {
- return asRlPtr(gz, scope, rl, result_ptr, rhs, dest_type);
+ return asRlPtr(gz, scope, rl, node, result_ptr, rhs, dest_type);
},
.block_ptr => |block_scope| {
- return asRlPtr(gz, scope, rl, block_scope.rl_ptr, rhs, dest_type);
+ return asRlPtr(gz, scope, rl, node, block_scope.rl_ptr, rhs, dest_type);
},
}
}
@@ -6679,6 +6693,7 @@ fn asRlPtr(
parent_gz: *GenZir,
scope: *Scope,
rl: ResultLoc,
+ src_node: ast.Node.Index,
result_ptr: Zir.Inst.Ref,
operand_node: ast.Node.Index,
dest_type: Zir.Inst.Ref,
@@ -6692,7 +6707,7 @@ fn asRlPtr(
defer as_scope.instructions.deinit(astgen.gpa);
as_scope.rl_ptr = try as_scope.addBin(.coerce_result_ptr, dest_type, result_ptr);
- const result = try expr(&as_scope, &as_scope.base, .{ .block_ptr = &as_scope }, operand_node);
+ const result = try reachableExpr(&as_scope, &as_scope.base, .{ .block_ptr = &as_scope }, operand_node, src_node);
const parent_zir = &parent_gz.instructions;
if (as_scope.rvalue_rl_count == 1) {
// Busted! This expression didn't actually need a pointer.
@@ -9607,27 +9622,3 @@ fn advanceSourceCursor(astgen: *AstGen, source: []const u8, end: usize) void {
astgen.source_line = line;
astgen.source_column = column;
}
-
-fn checkVarInitExpr(
- astgen: *AstGen,
- gz: GenZir,
- var_node: ast.Node.Index,
- init_node: ast.Node.Index,
- init_inst: Zir.Inst.Ref,
- var_name_text: []const u8,
-) !void {
- if (gz.refIsNoReturn(init_inst)) {
- return astgen.failNodeNotes(
- var_node,
- "useless {s}",
- .{var_name_text},
- &[_]u32{
- try astgen.errNoteNode(
- init_node,
- "control flow is diverted here",
- .{},
- ),
- },
- );
- }
-}
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
index 0c04f70a86..6a17551ca7 100644
--- a/test/compile_errors.zig
+++ b/test/compile_errors.zig
@@ -4831,7 +4831,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const a = return;
\\}
, &[_][]const u8{
- "tmp.zig:2:5: error: useless local constant",
+ "tmp.zig:2:5: error: unreachable code",
"tmp.zig:2:15: note: control flow is diverted here",
});
@@ -5058,6 +5058,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\export fn entry() void { _ = f(); }
, &[_][]const u8{
"tmp.zig:2:12: error: unreachable code",
+ "tmp.zig:2:21: note: control flow is diverted here",
});
cases.add("invalid builtin fn",
@@ -7143,9 +7144,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\export fn entry8() void {
\\ var h = (Foo {}).bar;
\\}
- \\export fn entry9() void {
- \\ var z: noreturn = return;
- \\}
\\const Opaque = opaque {};
\\const Foo = struct {
\\ fn bar(self: *const Foo) void {}
@@ -7161,7 +7159,15 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:17:4: error: variable of type 'Opaque' not allowed",
"tmp.zig:20:4: error: variable of type 'type' must be const or comptime",
"tmp.zig:23:4: error: variable of type '(bound fn(*const Foo) void)' must be const or comptime",
- "tmp.zig:26:22: error: unreachable code",
+ });
+
+ cases.add("variable with type 'noreturn'",
+ \\export fn entry9() void {
+ \\ var z: noreturn = return;
+ \\}
+ , &[_][]const u8{
+ "tmp.zig:2:5: error: unreachable code",
+ "tmp.zig:2:23: note: control flow is diverted here",
});
cases.add("wrong types given to atomic order args in cmpxchg",
From 22b20f20b66a0225fe1d57ab8773ac066c205bdd Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Mon, 28 Jun 2021 17:17:26 -0700
Subject: [PATCH 05/15] AstGen: fix missing compile error for unreachable
`@TypeOf` argument
---
doc/langref.html.in | 4 ++--
src/AstGen.zig | 5 +++--
2 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/doc/langref.html.in b/doc/langref.html.in
index 667b4cd2a7..31de76359e 100644
--- a/doc/langref.html.in
+++ b/doc/langref.html.in
@@ -4228,8 +4228,8 @@ test "type of unreachable" {
comptime {
// The type of unreachable is noreturn.
- // However this assertion will still fail because
- // evaluating unreachable at compile-time is a compile error.
+ // However this assertion will still fail to compile because
+ // unreachable expressions are compile errors.
assert(@TypeOf(unreachable) == noreturn);
}
diff --git a/src/AstGen.zig b/src/AstGen.zig
index 15b5b88d9a..7e599da78b 100644
--- a/src/AstGen.zig
+++ b/src/AstGen.zig
@@ -6786,13 +6786,14 @@ fn typeOf(
return gz.astgen.failNode(node, "expected at least 1 argument, found 0", .{});
}
if (params.len == 1) {
- const result = try gz.addUnNode(.typeof, try expr(gz, scope, .none, params[0]), node);
+ const expr_result = try reachableExpr(gz, scope, .none, params[0], node);
+ const result = try gz.addUnNode(.typeof, expr_result, node);
return rvalue(gz, rl, result, node);
}
const arena = gz.astgen.arena;
var items = try arena.alloc(Zir.Inst.Ref, params.len);
for (params) |param, param_i| {
- items[param_i] = try expr(gz, scope, .none, param);
+ items[param_i] = try reachableExpr(gz, scope, .none, param, node);
}
const result = try gz.addExtendedMultiOp(.typeof_peer, node, items);
From 8ce880ca753ce95138bf03d956cf363ea2dfde5a Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Wed, 30 Jun 2021 11:27:39 -0700
Subject: [PATCH 06/15] avoid calling into stage1 backend when AstGen fails
The motivation for this commit is that there exists source files which
produce ast-check errors, but crash stage1 or otherwise trigger stage1
bugs. Previously to this commit, Zig would run AstGen, collect the
compile errors, run stage1, report stage1 compile errors and exit if
any, and then report AstGen compile errors.
The main change in this commit is to report AstGen errors prior to
invoking stage1, and in fact if any AstGen errors occur, do not invoke
stage1 at all.
This caused most of the compile error tests to fail due to things such
as unused local variables and mismatched stage1/stage2 error messages.
It was taking a long time to update the test cases one-by-one, so I
took this opportunity to unify the stage1 and stage2 testing harness,
specifically with regards to compile errors. In this way we can start
keeping track of which tests pass for 1, 2, or both.
`zig build test-compile-errors` no longer works; it is now integrated
into `zig build test-stage2`.
This is one step closer to executing compile error tests in parallel; in
fact the ThreadPool object is already in scope.
There are some cases where the stage1 compile errors were actually
better; those are left failing in this commit, to be addressed in a
follow-up commit.
Other changes in this commit:
* build.zig: improve support for -Dstage1 used with the test step.
* AstGen: minor cosmetic changes to error messages.
* stage2: add -fstage1 and -fno-stage1 flags. This now allows one to
download a binary of the zig compiler and use the llvm backend of
self-hosted. This was also needed for hooking up the test harness.
However, I realized that stage1 calls exit() and also has memory
leaks, so had to complicate the test harness by not using this flag
after all and instead invoking as a child process.
- These CLI flags will disappear once we start shipping the
self-hosted compiler as the main compiler. Until then, they can be
used to try out the work-in-progress stage2.
* stage2: select the LLVM backend by default for release modes, as long
as the target architecture is supported by LLVM.
* test harness: support setting the optimize mode
---
build.zig | 32 +-
lib/std/zig/ast.zig | 2 +-
src/AstGen.zig | 6 +-
src/Compilation.zig | 61 +-
src/link.zig | 5 +-
src/link/MachO.zig | 2 +-
src/link/Wasm.zig | 2 +-
src/main.zig | 10 +-
src/stage1.zig | 13 +-
src/target.zig | 67 +
src/test.zig | 308 +++-
test/{stage2/test.zig => cases.zig} | 17 +-
test/compile_errors.zig | 2276 +++++++++++++++------------
test/tests.zig | 321 ----
14 files changed, 1709 insertions(+), 1413 deletions(-)
rename test/{stage2/test.zig => cases.zig} (99%)
diff --git a/build.zig b/build.zig
index dcc60e6622..40e1b36e71 100644
--- a/build.zig
+++ b/build.zig
@@ -40,7 +40,7 @@ pub fn build(b: *Builder) !void {
var test_stage2 = b.addTest("src/test.zig");
test_stage2.setBuildMode(mode);
- test_stage2.addPackagePath("stage2_tests", "test/stage2/test.zig");
+ test_stage2.addPackagePath("test_cases", "test/cases.zig");
const fmt_build_zig = b.addFmt(&[_][]const u8{"build.zig"});
@@ -113,11 +113,15 @@ pub fn build(b: *Builder) !void {
if (is_stage1) {
exe.addIncludeDir("src");
exe.addIncludeDir("deps/SoftFloat-3e/source/include");
+
+ test_stage2.addIncludeDir("src");
+ test_stage2.addIncludeDir("deps/SoftFloat-3e/source/include");
// This is intentionally a dummy path. stage1.zig tries to @import("compiler_rt") in case
// of being built by cmake. But when built by zig it's gonna get a compiler_rt so that
// is pointless.
exe.addPackagePath("compiler_rt", "src/empty.zig");
exe.defineCMacro("ZIG_LINK_MODE", "Static");
+ test_stage2.defineCMacro("ZIG_LINK_MODE", "Static");
const softfloat = b.addStaticLibrary("softfloat", null);
softfloat.setBuildMode(.ReleaseFast);
@@ -126,10 +130,15 @@ pub fn build(b: *Builder) !void {
softfloat.addIncludeDir("deps/SoftFloat-3e/source/8086");
softfloat.addIncludeDir("deps/SoftFloat-3e/source/include");
softfloat.addCSourceFiles(&softfloat_sources, &[_][]const u8{ "-std=c99", "-O3" });
+
exe.linkLibrary(softfloat);
+ test_stage2.linkLibrary(softfloat);
exe.addCSourceFiles(&stage1_sources, &exe_cflags);
exe.addCSourceFiles(&optimized_c_sources, &[_][]const u8{ "-std=c99", "-O3" });
+
+ test_stage2.addCSourceFiles(&stage1_sources, &exe_cflags);
+ test_stage2.addCSourceFiles(&optimized_c_sources, &[_][]const u8{ "-std=c99", "-O3" });
}
if (cmake_cfg) |cfg| {
// Inside this code path, we have to coordinate with system packaged LLVM, Clang, and LLD.
@@ -139,8 +148,8 @@ pub fn build(b: *Builder) !void {
b.addSearchPrefix(cfg.cmake_prefix_path);
}
- try addCmakeCfgOptionsToExe(b, cfg, tracy, exe);
- try addCmakeCfgOptionsToExe(b, cfg, tracy, test_stage2);
+ try addCmakeCfgOptionsToExe(b, cfg, exe);
+ try addCmakeCfgOptionsToExe(b, cfg, test_stage2);
} else {
// Here we are -Denable-llvm but no cmake integration.
try addStaticLlvmOptionsToExe(exe);
@@ -233,7 +242,9 @@ pub fn build(b: *Builder) !void {
const is_darling_enabled = b.option(bool, "enable-darling", "[Experimental] Use Darling to run cross compiled macOS tests") orelse false;
const glibc_multi_dir = b.option([]const u8, "enable-foreign-glibc", "Provide directory with glibc installations to run cross compiled tests that link glibc");
+ test_stage2.addBuildOption(bool, "enable_logging", enable_logging);
test_stage2.addBuildOption(bool, "skip_non_native", skip_non_native);
+ test_stage2.addBuildOption(bool, "skip_compile_errors", skip_compile_errors);
test_stage2.addBuildOption(bool, "is_stage1", is_stage1);
test_stage2.addBuildOption(bool, "omit_stage2", omit_stage2);
test_stage2.addBuildOption(bool, "have_llvm", enable_llvm);
@@ -243,7 +254,8 @@ pub fn build(b: *Builder) !void {
test_stage2.addBuildOption(u32, "mem_leak_frames", mem_leak_frames * 2);
test_stage2.addBuildOption(bool, "enable_darling", is_darling_enabled);
test_stage2.addBuildOption(?[]const u8, "glibc_multi_install_dir", glibc_multi_dir);
- test_stage2.addBuildOption([]const u8, "version", version);
+ test_stage2.addBuildOption([:0]const u8, "version", try b.allocator.dupeZ(u8, version));
+ test_stage2.addBuildOption(std.SemanticVersion, "semver", semver);
const test_stage2_step = b.step("test-stage2", "Run the stage2 compiler tests");
test_stage2_step.dependOn(&test_stage2.step);
@@ -339,9 +351,6 @@ pub fn build(b: *Builder) !void {
}
// tests for this feature are disabled until we have the self-hosted compiler available
// toolchain_step.dependOn(tests.addGenHTests(b, test_filter));
- if (!skip_compile_errors) {
- toolchain_step.dependOn(tests.addCompileErrorTests(b, test_filter, modes));
- }
const std_step = tests.addPkgTests(
b,
@@ -383,7 +392,6 @@ const exe_cflags = [_][]const u8{
fn addCmakeCfgOptionsToExe(
b: *Builder,
cfg: CMakeConfig,
- tracy: ?[]const u8,
exe: *std.build.LibExeObjStep,
) !void {
exe.addObjectFile(fs.path.join(b.allocator, &[_][]const u8{
@@ -397,7 +405,7 @@ fn addCmakeCfgOptionsToExe(
addCMakeLibraryList(exe, cfg.lld_libraries);
addCMakeLibraryList(exe, cfg.llvm_libraries);
- const need_cpp_includes = tracy != null;
+ const need_cpp_includes = true;
// System -lc++ must be used because in this code path we are attempting to link
// against system-provided LLVM, Clang, LLD.
@@ -486,9 +494,9 @@ fn addCxxKnownPath(
if (need_cpp_includes) {
// I used these temporarily for testing something but we obviously need a
// more general purpose solution here.
- //exe.addIncludeDir("/nix/store/b3zsk4ihlpiimv3vff86bb5bxghgdzb9-gcc-9.2.0/lib/gcc/x86_64-unknown-linux-gnu/9.2.0/../../../../include/c++/9.2.0");
- //exe.addIncludeDir("/nix/store/b3zsk4ihlpiimv3vff86bb5bxghgdzb9-gcc-9.2.0/lib/gcc/x86_64-unknown-linux-gnu/9.2.0/../../../../include/c++/9.2.0/x86_64-unknown-linux-gnu");
- //exe.addIncludeDir("/nix/store/b3zsk4ihlpiimv3vff86bb5bxghgdzb9-gcc-9.2.0/lib/gcc/x86_64-unknown-linux-gnu/9.2.0/../../../../include/c++/9.2.0/backward");
+ //exe.addIncludeDir("/nix/store/fvf3qjqa5qpcjjkq37pb6ypnk1mzhf5h-gcc-9.3.0/lib/gcc/x86_64-unknown-linux-gnu/9.3.0/../../../../include/c++/9.3.0");
+ //exe.addIncludeDir("/nix/store/fvf3qjqa5qpcjjkq37pb6ypnk1mzhf5h-gcc-9.3.0/lib/gcc/x86_64-unknown-linux-gnu/9.3.0/../../../../include/c++/9.3.0/x86_64-unknown-linux-gnu");
+ //exe.addIncludeDir("/nix/store/fvf3qjqa5qpcjjkq37pb6ypnk1mzhf5h-gcc-9.3.0/lib/gcc/x86_64-unknown-linux-gnu/9.3.0/../../../../include/c++/9.3.0/backward");
}
}
diff --git a/lib/std/zig/ast.zig b/lib/std/zig/ast.zig
index 59fe2fdff1..512e4ec265 100644
--- a/lib/std/zig/ast.zig
+++ b/lib/std/zig/ast.zig
@@ -284,7 +284,7 @@ pub const Tree = struct {
return stream.writeAll("bit range not allowed on slices and arrays");
},
.invalid_token => {
- return stream.print("invalid token '{s}'", .{
+ return stream.print("invalid token: '{s}'", .{
token_tags[parse_error.token].symbol(),
});
},
diff --git a/src/AstGen.zig b/src/AstGen.zig
index 7e599da78b..64f5f012f0 100644
--- a/src/AstGen.zig
+++ b/src/AstGen.zig
@@ -4570,7 +4570,7 @@ fn tryExpr(
return astgen.failNode(node, "invalid 'try' outside function scope", .{});
};
- if (parent_gz.in_defer) return astgen.failNode(node, "try is not allowed inside defer expression", .{});
+ if (parent_gz.in_defer) return astgen.failNode(node, "'try' is not allowed inside defer expression", .{});
var block_scope = parent_gz.makeSubBlock(scope);
block_scope.setBreakResultLoc(rl);
@@ -6199,7 +6199,7 @@ fn identifier(
const ident_token = main_tokens[ident];
const ident_name = try astgen.identifierTokenString(ident_token);
if (mem.eql(u8, ident_name, "_")) {
- return astgen.failNode(ident, "'_' may not be used as an identifier", .{});
+ return astgen.failNode(ident, "'_' used as an identifier without @\"_\" syntax", .{});
}
if (simple_types.get(ident_name)) |zir_const_ref| {
@@ -6827,7 +6827,7 @@ fn builtinCall(
if (info.param_count) |expected| {
if (expected != params.len) {
const s = if (expected == 1) "" else "s";
- return astgen.failNode(node, "expected {d} parameter{s}, found {d}", .{
+ return astgen.failNode(node, "expected {d} argument{s}, found {d}", .{
expected, s, params.len,
});
}
diff --git a/src/Compilation.zig b/src/Compilation.zig
index 065890d9fe..c1cca84f62 100644
--- a/src/Compilation.zig
+++ b/src/Compilation.zig
@@ -670,6 +670,7 @@ pub const InitOptions = struct {
use_llvm: ?bool = null,
use_lld: ?bool = null,
use_clang: ?bool = null,
+ use_stage1: ?bool = null,
rdynamic: bool = false,
strip: bool = false,
single_threaded: bool = false,
@@ -807,8 +808,22 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
const ofmt = options.object_format orelse options.target.getObjectFormat();
+ const use_stage1 = options.use_stage1 orelse blk: {
+ if (build_options.omit_stage2)
+ break :blk true;
+ if (options.use_llvm) |use_llvm| {
+ if (!use_llvm) {
+ break :blk false;
+ }
+ }
+ break :blk build_options.is_stage1;
+ };
+
// Make a decision on whether to use LLVM or our own backend.
- const use_llvm = if (options.use_llvm) |explicit| explicit else blk: {
+ const use_llvm = build_options.have_llvm and blk: {
+ if (options.use_llvm) |explicit|
+ break :blk explicit;
+
// If we have no zig code to compile, no need for LLVM.
if (options.root_pkg == null)
break :blk false;
@@ -817,18 +832,24 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
if (ofmt == .c)
break :blk false;
- // If we are the stage1 compiler, we depend on the stage1 c++ llvm backend
+ // The stage1 compiler depends on the stage1 C++ LLVM backend
// to compile zig code.
- if (build_options.is_stage1)
+ if (use_stage1)
+ break :blk true;
+
+ // Prefer LLVM for release builds as long as it supports the target architecture.
+ if (options.optimize_mode != .Debug and target_util.hasLlvmSupport(options.target))
break :blk true;
- // We would want to prefer LLVM for release builds when it is available, however
- // we don't have an LLVM backend yet :)
- // We would also want to prefer LLVM for architectures that we don't have self-hosted support for too.
break :blk false;
};
- if (!use_llvm and options.machine_code_model != .default) {
- return error.MachineCodeModelNotSupported;
+ if (!use_llvm) {
+ if (options.use_llvm == true) {
+ return error.ZigCompilerNotBuiltWithLLVMExtensions;
+ }
+ if (options.machine_code_model != .default) {
+ return error.MachineCodeModelNotSupportedWithoutLlvm;
+ }
}
const tsan = options.want_tsan orelse false;
@@ -1344,6 +1365,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
.subsystem = options.subsystem,
.is_test = options.is_test,
.wasi_exec_model = wasi_exec_model,
+ .use_stage1 = use_stage1,
});
errdefer bin_file.destroy();
comp.* = .{
@@ -1486,9 +1508,9 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
try comp.work_queue.writeItem(.libtsan);
}
- // The `is_stage1` condition is here only because stage2 cannot yet build compiler-rt.
+ // The `use_stage1` condition is here only because stage2 cannot yet build compiler-rt.
// Once it is capable this condition should be removed.
- if (build_options.is_stage1) {
+ if (comp.bin_file.options.use_stage1) {
if (comp.bin_file.options.include_compiler_rt) {
if (is_exe_or_dyn_lib) {
try comp.work_queue.writeItem(.{ .compiler_rt_lib = {} });
@@ -1519,7 +1541,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
}
}
- if (build_options.is_stage1 and comp.bin_file.options.use_llvm) {
+ if (comp.bin_file.options.use_stage1) {
try comp.work_queue.writeItem(.{ .stage1_module = {} });
}
@@ -1625,8 +1647,7 @@ pub fn update(self: *Compilation) !void {
self.c_object_work_queue.writeItemAssumeCapacity(key);
}
- const use_stage1 = build_options.omit_stage2 or
- (build_options.is_stage1 and self.bin_file.options.use_llvm);
+ const use_stage1 = build_options.is_stage1 and self.bin_file.options.use_stage1;
if (self.bin_file.options.module) |module| {
module.compile_log_text.shrinkAndFree(module.gpa, 0);
module.generation += 1;
@@ -1921,7 +1942,7 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
// (at least for now) single-threaded main work queue. However, C object compilation
// only needs to be finished by the end of this function.
- var zir_prog_node = main_progress_node.start("AST Lowering", self.astgen_work_queue.count);
+ var zir_prog_node = main_progress_node.start("AST Lowering", 0);
defer zir_prog_node.end();
var c_obj_prog_node = main_progress_node.start("Compile C Objects", self.c_source_files.len);
@@ -1949,13 +1970,18 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
}
}
- const use_stage1 = build_options.omit_stage2 or
- (build_options.is_stage1 and self.bin_file.options.use_llvm);
+ const use_stage1 = build_options.is_stage1 and self.bin_file.options.use_stage1;
if (!use_stage1) {
// Iterate over all the files and look for outdated and deleted declarations.
if (self.bin_file.options.module) |mod| {
try mod.processOutdatedAndDeletedDecls();
}
+ } else if (self.bin_file.options.module) |mod| {
+ // If there are any AstGen compile errors, report them now to avoid
+ // hitting stage1 bugs.
+ if (mod.failed_files.count() != 0) {
+ return;
+ }
}
while (self.work_queue.readItem()) |work_item| switch (work_item) {
@@ -3486,8 +3512,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) Alloc
const target = comp.getTarget();
const generic_arch_name = target.cpu.arch.genericName();
- const use_stage1 = build_options.omit_stage2 or
- (build_options.is_stage1 and comp.bin_file.options.use_llvm);
+ const use_stage1 = build_options.is_stage1 and comp.bin_file.options.use_stage1;
@setEvalBranchQuota(4000);
try buffer.writer().print(
diff --git a/src/link.zig b/src/link.zig
index d429a1b459..9c1be16b9c 100644
--- a/src/link.zig
+++ b/src/link.zig
@@ -92,6 +92,7 @@ pub const Options = struct {
each_lib_rpath: bool,
disable_lld_caching: bool,
is_test: bool,
+ use_stage1: bool,
major_subsystem_version: ?u32,
minor_subsystem_version: ?u32,
gc_sections: ?bool = null,
@@ -181,7 +182,7 @@ pub const File = struct {
/// rewriting it. A malicious file is detected as incremental link failure
/// and does not cause Illegal Behavior. This operation is not atomic.
pub fn openPath(allocator: *Allocator, options: Options) !*File {
- const use_stage1 = build_options.is_stage1 and options.use_llvm;
+ const use_stage1 = build_options.is_stage1 and options.use_stage1;
if (use_stage1 or options.emit == null) {
return switch (options.object_format) {
.coff, .pe => &(try Coff.createEmpty(allocator, options)).base,
@@ -507,7 +508,7 @@ pub const File = struct {
// If there is no Zig code to compile, then we should skip flushing the output file because it
// will not be part of the linker line anyway.
const module_obj_path: ?[]const u8 = if (base.options.module) |module| blk: {
- const use_stage1 = build_options.is_stage1 and base.options.use_llvm;
+ const use_stage1 = build_options.is_stage1 and base.options.use_stage1;
if (use_stage1) {
const obj_basename = try std.zig.binNameAlloc(arena, .{
.root_name = base.options.root_name,
diff --git a/src/link/MachO.zig b/src/link/MachO.zig
index ba9999730e..df2e0134e4 100644
--- a/src/link/MachO.zig
+++ b/src/link/MachO.zig
@@ -606,7 +606,7 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void {
// If there is no Zig code to compile, then we should skip flushing the output file because it
// will not be part of the linker line anyway.
const module_obj_path: ?[]const u8 = if (self.base.options.module) |module| blk: {
- const use_stage1 = build_options.is_stage1 and self.base.options.use_llvm;
+ const use_stage1 = build_options.is_stage1 and self.base.options.use_stage1;
if (use_stage1) {
const obj_basename = try std.zig.binNameAlloc(arena, .{
.root_name = self.base.options.root_name,
diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig
index 5758f81a95..15a36a4bcc 100644
--- a/src/link/Wasm.zig
+++ b/src/link/Wasm.zig
@@ -556,7 +556,7 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
// If there is no Zig code to compile, then we should skip flushing the output file because it
// will not be part of the linker line anyway.
const module_obj_path: ?[]const u8 = if (self.base.options.module) |module| blk: {
- const use_stage1 = build_options.is_stage1 and self.base.options.use_llvm;
+ const use_stage1 = build_options.is_stage1 and self.base.options.use_stage1;
if (use_stage1) {
const obj_basename = try std.zig.binNameAlloc(arena, .{
.root_name = self.base.options.root_name,
diff --git a/src/main.zig b/src/main.zig
index 902d893169..760ad79a3a 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -350,9 +350,11 @@ const usage_build_generic =
\\ -funwind-tables Always produce unwind table entries for all functions
\\ -fno-unwind-tables Never produce unwind table entries
\\ -fLLVM Force using LLVM as the codegen backend
- \\ -fno-LLVM Prevent using LLVM as a codegen backend
+ \\ -fno-LLVM Prevent using LLVM as the codegen backend
\\ -fClang Force using Clang as the C/C++ compilation backend
\\ -fno-Clang Prevent using Clang as the C/C++ compilation backend
+ \\ -fstage1 Force using bootstrap compiler as the codegen backend
+ \\ -fno-stage1 Prevent using bootstrap compiler as the codegen backend
\\ --strip Omit debug symbols
\\ --single-threaded Code assumes it is only used single-threaded
\\ -ofmt=[mode] Override target object format
@@ -602,6 +604,7 @@ fn buildOutputType(
var use_llvm: ?bool = null;
var use_lld: ?bool = null;
var use_clang: ?bool = null;
+ var use_stage1: ?bool = null;
var link_eh_frame_hdr = false;
var link_emit_relocs = false;
var each_lib_rpath: ?bool = null;
@@ -975,6 +978,10 @@ fn buildOutputType(
use_clang = true;
} else if (mem.eql(u8, arg, "-fno-Clang")) {
use_clang = false;
+ } else if (mem.eql(u8, arg, "-fstage1")) {
+ use_stage1 = true;
+ } else if (mem.eql(u8, arg, "-fno-stage1")) {
+ use_stage1 = false;
} else if (mem.eql(u8, arg, "-rdynamic")) {
rdynamic = true;
} else if (mem.eql(u8, arg, "-fsoname")) {
@@ -2020,6 +2027,7 @@ fn buildOutputType(
.use_llvm = use_llvm,
.use_lld = use_lld,
.use_clang = use_clang,
+ .use_stage1 = use_stage1,
.rdynamic = rdynamic,
.linker_script = linker_script,
.version_script = version_script,
diff --git a/src/stage1.zig b/src/stage1.zig
index 46d70ea335..2284e512ec 100644
--- a/src/stage1.zig
+++ b/src/stage1.zig
@@ -7,6 +7,7 @@ const assert = std.debug.assert;
const mem = std.mem;
const CrossTarget = std.zig.CrossTarget;
const Target = std.Target;
+const builtin = @import("builtin");
const build_options = @import("build_options");
const stage2 = @import("main.zig");
@@ -16,16 +17,19 @@ const translate_c = @import("translate_c.zig");
const target_util = @import("target.zig");
comptime {
- assert(std.builtin.link_libc);
+ assert(builtin.link_libc);
assert(build_options.is_stage1);
assert(build_options.have_llvm);
- _ = @import("compiler_rt");
+ if (!builtin.is_test) {
+ _ = @import("compiler_rt");
+ @export(main, .{ .name = "main" });
+ }
}
pub const log = stage2.log;
pub const log_level = stage2.log_level;
-pub export fn main(argc: c_int, argv: [*][*:0]u8) c_int {
+pub fn main(argc: c_int, argv: [*][*:0]u8) callconv(.C) c_int {
std.os.argv = argv[0..@intCast(usize, argc)];
std.debug.maybeEnableSegfaultHandler();
@@ -41,7 +45,7 @@ pub export fn main(argc: c_int, argv: [*][*:0]u8) c_int {
for (args) |*arg, i| {
arg.* = mem.spanZ(argv[i]);
}
- if (std.builtin.mode == .Debug) {
+ if (builtin.mode == .Debug) {
stage2.mainArgs(gpa, arena, args) catch unreachable;
} else {
stage2.mainArgs(gpa, arena, args) catch |err| fatal("{s}", .{@errorName(err)});
@@ -147,6 +151,7 @@ pub const Module = extern struct {
}
};
+pub const os_init = zig_stage1_os_init;
extern fn zig_stage1_os_init() void;
pub const create = zig_stage1_create;
diff --git a/src/target.zig b/src/target.zig
index d7c39d62a0..a61bbe7f09 100644
--- a/src/target.zig
+++ b/src/target.zig
@@ -170,6 +170,73 @@ pub fn hasValgrindSupport(target: std.Target) bool {
}
}
+/// The set of targets that LLVM has non-experimental support for.
+/// Used to select between LLVM backend and self-hosted backend when compiling in
+/// release modes.
+pub fn hasLlvmSupport(target: std.Target) bool {
+ return switch (target.cpu.arch) {
+ .arm,
+ .armeb,
+ .aarch64,
+ .aarch64_be,
+ .aarch64_32,
+ .arc,
+ .avr,
+ .bpfel,
+ .bpfeb,
+ .csky,
+ .hexagon,
+ .mips,
+ .mipsel,
+ .mips64,
+ .mips64el,
+ .msp430,
+ .powerpc,
+ .powerpcle,
+ .powerpc64,
+ .powerpc64le,
+ .r600,
+ .amdgcn,
+ .riscv32,
+ .riscv64,
+ .sparc,
+ .sparcv9,
+ .sparcel,
+ .s390x,
+ .tce,
+ .tcele,
+ .thumb,
+ .thumbeb,
+ .i386,
+ .x86_64,
+ .xcore,
+ .nvptx,
+ .nvptx64,
+ .le32,
+ .le64,
+ .amdil,
+ .amdil64,
+ .hsail,
+ .hsail64,
+ .spir,
+ .spir64,
+ .kalimba,
+ .shave,
+ .lanai,
+ .wasm32,
+ .wasm64,
+ .renderscript32,
+ .renderscript64,
+ .ve,
+ => true,
+
+ .spu_2,
+ .spirv32,
+ .spirv64,
+ => false,
+ };
+}
+
pub fn supportsStackProbing(target: std.Target) bool {
return target.os.tag != .windows and target.os.tag != .uefi and
(target.cpu.arch == .i386 or target.cpu.arch == .x86_64);
diff --git a/src/test.zig b/src/test.zig
index 1d2a552662..19135e3d7e 100644
--- a/src/test.zig
+++ b/src/test.zig
@@ -10,18 +10,25 @@ const enable_wine: bool = build_options.enable_wine;
const enable_wasmtime: bool = build_options.enable_wasmtime;
const enable_darling: bool = build_options.enable_darling;
const glibc_multi_install_dir: ?[]const u8 = build_options.glibc_multi_install_dir;
+const skip_compile_errors = build_options.skip_compile_errors;
const ThreadPool = @import("ThreadPool.zig");
const CrossTarget = std.zig.CrossTarget;
+const print = std.debug.print;
+const assert = std.debug.assert;
const zig_h = link.File.C.zig_h;
const hr = "=" ** 80;
-test "self-hosted" {
+test {
+ if (build_options.is_stage1) {
+ @import("stage1.zig").os_init();
+ }
+
var ctx = TestContext.init();
defer ctx.deinit();
- try @import("stage2_tests").addCases(&ctx);
+ try @import("test_cases").addCases(&ctx);
try ctx.run();
}
@@ -83,14 +90,13 @@ const ErrorMsg = union(enum) {
});
},
.plain => |plain| {
- return writer.print("{s}: {s}", .{ plain.msg, @tagName(plain.kind) });
+ return writer.print("{s}: {s}", .{ @tagName(plain.kind), plain.msg });
},
}
}
};
pub const TestContext = struct {
- /// TODO: find a way to treat cases as individual tests (shouldn't show "1 test passed" if there are 200 cases)
cases: std.ArrayList(Case),
pub const Update = struct {
@@ -127,6 +133,12 @@ pub const TestContext = struct {
path: []const u8,
};
+ pub const Backend = enum {
+ stage1,
+ stage2,
+ llvm,
+ };
+
/// A `Case` consists of a list of `Update`. The same `Compilation` is used for each
/// update, so each update's source is treated as a single file being
/// updated by the test harness and incrementally compiled.
@@ -140,13 +152,20 @@ pub const TestContext = struct {
/// In order to be able to run e.g. Execution updates, this must be set
/// to Executable.
output_mode: std.builtin.OutputMode,
+ optimize_mode: std.builtin.Mode = .Debug,
updates: std.ArrayList(Update),
object_format: ?std.Target.ObjectFormat = null,
emit_h: bool = false,
- llvm_backend: bool = false,
+ is_test: bool = false,
+ expect_exact: bool = false,
+ backend: Backend = .stage2,
files: std.ArrayList(File),
+ pub fn addSourceFile(case: *Case, name: []const u8, src: [:0]const u8) void {
+ case.files.append(.{ .path = name, .src = src }) catch @panic("out of memory");
+ }
+
/// Adds a subcase in which the module is updated with `src`, and a C
/// header is generated.
pub fn addHeader(self: *Case, src: [:0]const u8, result: [:0]const u8) void {
@@ -254,11 +273,6 @@ pub const TestContext = struct {
return ctx.addExe(name, target);
}
- /// Adds a test case for ZIR input, producing an executable
- pub fn exeZIR(ctx: *TestContext, name: []const u8, target: CrossTarget) *Case {
- return ctx.addExe(name, target, .ZIR);
- }
-
pub fn exeFromCompiledC(ctx: *TestContext, name: []const u8, target: CrossTarget) *Case {
const prefixed_name = std.fmt.allocPrint(ctx.cases.allocator, "CBE: {s}", .{name}) catch
@panic("out of memory");
@@ -282,7 +296,7 @@ pub const TestContext = struct {
.updates = std.ArrayList(Update).init(ctx.cases.allocator),
.output_mode = .Exe,
.files = std.ArrayList(File).init(ctx.cases.allocator),
- .llvm_backend = true,
+ .backend = .llvm,
}) catch @panic("out of memory");
return &ctx.cases.items[ctx.cases.items.len - 1];
}
@@ -302,6 +316,22 @@ pub const TestContext = struct {
return &ctx.cases.items[ctx.cases.items.len - 1];
}
+ pub fn addTest(
+ ctx: *TestContext,
+ name: []const u8,
+ target: CrossTarget,
+ ) *Case {
+ ctx.cases.append(Case{
+ .name = name,
+ .target = target,
+ .updates = std.ArrayList(Update).init(ctx.cases.allocator),
+ .output_mode = .Exe,
+ .is_test = true,
+ .files = std.ArrayList(File).init(ctx.cases.allocator),
+ }) catch @panic("out of memory");
+ return &ctx.cases.items[ctx.cases.items.len - 1];
+ }
+
/// Adds a test case for Zig input, producing an object file.
pub fn obj(ctx: *TestContext, name: []const u8, target: CrossTarget) *Case {
return ctx.addObj(name, target);
@@ -333,6 +363,45 @@ pub const TestContext = struct {
ctx.addC(name, target).addHeader(src, zig_h ++ out);
}
+ pub fn objErrStage1(
+ ctx: *TestContext,
+ name: []const u8,
+ src: [:0]const u8,
+ expected_errors: []const []const u8,
+ ) void {
+ if (skip_compile_errors) return;
+
+ const case = ctx.addObj(name, .{});
+ case.backend = .stage1;
+ case.addError(src, expected_errors);
+ }
+
+ pub fn testErrStage1(
+ ctx: *TestContext,
+ name: []const u8,
+ src: [:0]const u8,
+ expected_errors: []const []const u8,
+ ) void {
+ if (skip_compile_errors) return;
+
+ const case = ctx.addTest(name, .{});
+ case.backend = .stage1;
+ case.addError(src, expected_errors);
+ }
+
+ pub fn exeErrStage1(
+ ctx: *TestContext,
+ name: []const u8,
+ src: [:0]const u8,
+ expected_errors: []const []const u8,
+ ) void {
+ if (skip_compile_errors) return;
+
+ const case = ctx.addExe(name, .{});
+ case.backend = .stage1;
+ case.addError(src, expected_errors);
+ }
+
pub fn addCompareOutput(
ctx: *TestContext,
name: []const u8,
@@ -386,18 +455,6 @@ pub const TestContext = struct {
ctx.addTransform(name, target, src, result);
}
- /// Adds a test case that cleans up the ZIR source given in `src`, and
- /// tests the resulting ZIR against `result`
- pub fn transformZIR(
- ctx: *TestContext,
- name: []const u8,
- target: CrossTarget,
- src: [:0]const u8,
- result: [:0]const u8,
- ) void {
- ctx.addTransform(name, target, .ZIR, src, result);
- }
-
pub fn addError(
ctx: *TestContext,
name: []const u8,
@@ -555,7 +612,7 @@ pub const TestContext = struct {
continue;
// Skip tests that require LLVM backend when it is not available
- if (!build_options.have_llvm and case.llvm_backend)
+ if (!build_options.have_llvm and case.backend == .llvm)
continue;
var prg_node = root_node.start(case.name, case.updates.items.len);
@@ -567,7 +624,7 @@ pub const TestContext = struct {
progress.initial_delay_ns = 0;
progress.refresh_rate_ns = 0;
- self.runOneCase(
+ runOneCase(
std.testing.allocator,
&prg_node,
case,
@@ -576,17 +633,16 @@ pub const TestContext = struct {
global_cache_directory,
) catch |err| {
fail_count += 1;
- std.debug.print("test '{s}' failed: {s}\n\n", .{ case.name, @errorName(err) });
+ print("test '{s}' failed: {s}\n\n", .{ case.name, @errorName(err) });
};
}
if (fail_count != 0) {
- std.debug.print("{d} tests failed\n", .{fail_count});
+ print("{d} tests failed\n", .{fail_count});
return error.TestFailed;
}
}
fn runOneCase(
- self: *TestContext,
allocator: *Allocator,
root_node: *std.Progress.Node,
case: Case,
@@ -594,7 +650,6 @@ pub const TestContext = struct {
thread_pool: *ThreadPool,
global_cache_directory: Compilation.Directory,
) !void {
- _ = self;
const target_info = try std.zig.system.NativeTargetInfo.detect(allocator, case.target);
const target = target_info.target;
@@ -607,14 +662,137 @@ pub const TestContext = struct {
var cache_dir = try tmp.dir.makeOpenPath("zig-cache", .{});
defer cache_dir.close();
- const tmp_dir_path = try std.fs.path.join(arena, &[_][]const u8{ ".", "zig-cache", "tmp", &tmp.sub_path });
+
+ const tmp_dir_path = try std.fs.path.join(
+ arena,
+ &[_][]const u8{ ".", "zig-cache", "tmp", &tmp.sub_path },
+ );
+ const local_cache_path = try std.fs.path.join(
+ arena,
+ &[_][]const u8{ tmp_dir_path, "zig-cache" },
+ );
+
+ for (case.files.items) |file| {
+ try tmp.dir.writeFile(file.path, file.src);
+ }
+
+ if (case.backend == .stage1) {
+ // stage1 backend has limitations:
+ // * leaks memory
+ // * calls exit() when a compile error happens
+ // * cannot handle updates
+ // because of this we must spawn a child process rather than
+ // using Compilation directly.
+ assert(case.updates.items.len == 1);
+ const update = case.updates.items[0];
+ try tmp.dir.writeFile(tmp_src_path, update.src);
+
+ var zig_args = std.ArrayList([]const u8).init(arena);
+ try zig_args.append(std.testing.zig_exe_path);
+
+ if (case.is_test) {
+ try zig_args.append("test");
+ } else switch (case.output_mode) {
+ .Obj => try zig_args.append("build-obj"),
+ .Exe => try zig_args.append("build-exe"),
+ .Lib => try zig_args.append("build-lib"),
+ }
+
+ try zig_args.append(try std.fs.path.join(arena, &.{ tmp_dir_path, tmp_src_path }));
+
+ try zig_args.append("--name");
+ try zig_args.append("test");
+
+ try zig_args.append("--cache-dir");
+ try zig_args.append(local_cache_path);
+
+ try zig_args.append("--global-cache-dir");
+ try zig_args.append(global_cache_directory.path orelse ".");
+
+ if (!case.target.isNative()) {
+ try zig_args.append("-target");
+ try zig_args.append(try target.zigTriple(arena));
+ }
+
+ try zig_args.append("-O");
+ try zig_args.append(@tagName(case.optimize_mode));
+
+ const result = try std.ChildProcess.exec(.{
+ .allocator = arena,
+ .argv = zig_args.items,
+ });
+ switch (update.case) {
+ .Error => |case_error_list| {
+ switch (result.term) {
+ .Exited => |code| {
+ if (code == 0) {
+ dumpArgs(zig_args.items);
+ return error.CompilationIncorrectlySucceeded;
+ }
+ },
+ else => {
+ dumpArgs(zig_args.items);
+ return error.CompilationCrashed;
+ },
+ }
+ var ok = true;
+ if (case.expect_exact) {
+ var err_iter = ErrLineIter.init(result.stderr);
+ var i: usize = 0;
+ ok = while (err_iter.next()) |line| : (i += 1) {
+ if (i >= case_error_list.len) break false;
+ const expected = try std.fmt.allocPrint(arena, "{s}", .{case_error_list[i]});
+ if (std.mem.indexOf(u8, line, expected) == null) break false;
+ continue;
+ } else true;
+
+ ok = ok and i == case_error_list.len;
+
+ if (!ok) {
+ print("\n======== Expected these compile errors: ========\n", .{});
+ for (case_error_list) |msg| {
+ const expected = try std.fmt.allocPrint(arena, "{s}", .{msg});
+ print("{s}\n", .{expected});
+ }
+ }
+ } else {
+ for (case_error_list) |msg| {
+ const expected = try std.fmt.allocPrint(arena, "{s}", .{msg});
+ if (std.mem.indexOf(u8, result.stderr, expected) == null) {
+ print(
+ \\
+ \\=========== Expected compile error: ============
+ \\{s}
+ \\
+ , .{expected});
+ ok = false;
+ break;
+ }
+ }
+ }
+
+ if (!ok) {
+ print(
+ \\================= Full output: =================
+ \\{s}
+ \\================================================
+ \\
+ , .{result.stderr});
+ return error.TestFailed;
+ }
+ },
+ .CompareObjectFile => @panic("TODO implement in the test harness"),
+ .Execution => @panic("TODO implement in the test harness"),
+ .Header => @panic("TODO implement in the test harness"),
+ }
+ return;
+ }
+
const zig_cache_directory: Compilation.Directory = .{
.handle = cache_dir,
- .path = try std.fs.path.join(arena, &[_][]const u8{ tmp_dir_path, "zig-cache" }),
+ .path = local_cache_path,
};
- const tmp_src_path = "test_case.zig";
-
var root_pkg: Package = .{
.root_src_directory = .{ .path = tmp_dir_path, .handle = tmp.dir },
.root_src_path = tmp_src_path,
@@ -640,6 +818,14 @@ pub const TestContext = struct {
.directory = emit_directory,
.basename = "test_case.h",
} else null;
+ const use_llvm: ?bool = switch (case.backend) {
+ .llvm => true,
+ else => null,
+ };
+ const use_stage1: ?bool = switch (case.backend) {
+ .stage1 => true,
+ else => null,
+ };
const comp = try Compilation.create(allocator, .{
.local_cache_directory = zig_cache_directory,
.global_cache_directory = global_cache_directory,
@@ -651,8 +837,8 @@ pub const TestContext = struct {
// and linking. This will require a rework to support multi-file
// tests.
.output_mode = case.output_mode,
- // TODO: support testing optimizations
- .optimize_mode = .Debug,
+ .is_test = case.is_test,
+ .optimize_mode = case.optimize_mode,
.emit_bin = emit_bin,
.emit_h = emit_h,
.root_pkg = &root_pkg,
@@ -661,17 +847,13 @@ pub const TestContext = struct {
.is_native_os = case.target.isNativeOs(),
.is_native_abi = case.target.isNativeAbi(),
.dynamic_linker = target_info.dynamic_linker.get(),
- .link_libc = case.llvm_backend,
- .use_llvm = case.llvm_backend,
- .use_lld = case.llvm_backend,
+ .link_libc = case.backend == .llvm,
+ .use_llvm = use_llvm,
+ .use_stage1 = use_stage1,
.self_exe_path = std.testing.zig_exe_path,
});
defer comp.destroy();
- for (case.files.items) |file| {
- try tmp.dir.writeFile(file.path, file.src);
- }
-
for (case.updates.items) |update, update_index| {
var update_node = root_node.start("update", 3);
update_node.activate();
@@ -692,19 +874,19 @@ pub const TestContext = struct {
var all_errors = try comp.getAllErrorsAlloc();
defer all_errors.deinit(allocator);
if (all_errors.list.len != 0) {
- std.debug.print(
+ print(
"\nCase '{s}': unexpected errors at update_index={d}:\n{s}\n",
.{ case.name, update_index, hr },
);
for (all_errors.list) |err_msg| {
switch (err_msg) {
.src => |src| {
- std.debug.print("{s}:{d}:{d}: error: {s}\n{s}\n", .{
+ print("{s}:{d}:{d}: error: {s}\n{s}\n", .{
src.src_path, src.line + 1, src.column + 1, src.msg, hr,
});
},
.plain => |plain| {
- std.debug.print("error: {s}\n{s}\n", .{ plain.msg, hr });
+ print("error: {s}\n{s}\n", .{ plain.msg, hr });
},
}
}
@@ -779,7 +961,7 @@ pub const TestContext = struct {
},
}
} else {
- std.debug.print(
+ print(
"\nUnexpected error:\n{s}\n{}\n{s}",
.{ hr, ErrorMsg.init(actual_error, .@"error"), hr },
);
@@ -817,7 +999,7 @@ pub const TestContext = struct {
},
}
} else {
- std.debug.print(
+ print(
"\nUnexpected note:\n{s}\n{}\n{s}",
.{ hr, ErrorMsg.init(note.*, .note), hr },
);
@@ -827,7 +1009,7 @@ pub const TestContext = struct {
for (handled_errors) |handled, i| {
if (!handled) {
- std.debug.print(
+ print(
"\nExpected error not found:\n{s}\n{}\n{s}",
.{ hr, case_error_list[i], hr },
);
@@ -836,7 +1018,7 @@ pub const TestContext = struct {
}
if (any_failed) {
- std.debug.print("\nupdate_index={d} ", .{update_index});
+ print("\nupdate_index={d} ", .{update_index});
return error.WrongCompileErrors;
}
},
@@ -932,7 +1114,7 @@ pub const TestContext = struct {
.cwd_dir = tmp.dir,
.cwd = tmp_dir_path,
}) catch |err| {
- std.debug.print("\nupdate_index={d} The following command failed with {s}:\n", .{
+ print("\nupdate_index={d} The following command failed with {s}:\n", .{
update_index, @errorName(err),
});
dumpArgs(argv.items);
@@ -947,7 +1129,7 @@ pub const TestContext = struct {
switch (exec_result.term) {
.Exited => |code| {
if (code != 0) {
- std.debug.print("\n{s}\n{s}: execution exited with code {d}:\n", .{
+ print("\n{s}\n{s}: execution exited with code {d}:\n", .{
exec_result.stderr, case.name, code,
});
dumpArgs(argv.items);
@@ -955,7 +1137,7 @@ pub const TestContext = struct {
}
},
else => {
- std.debug.print("\n{s}\n{s}: execution crashed:\n", .{
+ print("\n{s}\n{s}: execution crashed:\n", .{
exec_result.stderr, case.name,
});
dumpArgs(argv.items);
@@ -974,7 +1156,25 @@ pub const TestContext = struct {
fn dumpArgs(argv: []const []const u8) void {
for (argv) |arg| {
- std.debug.print("{s} ", .{arg});
+ print("{s} ", .{arg});
}
- std.debug.print("\n", .{});
+ print("\n", .{});
}
+
+const tmp_src_path = "tmp.zig";
+
+const ErrLineIter = struct {
+ lines: std.mem.SplitIterator,
+
+ fn init(input: []const u8) ErrLineIter {
+ return ErrLineIter{ .lines = std.mem.split(input, "\n") };
+ }
+
+ fn next(self: *ErrLineIter) ?[]const u8 {
+ while (self.lines.next()) |line| {
+ if (std.mem.indexOf(u8, line, tmp_src_path) != null)
+ return line;
+ }
+ return null;
+ }
+};
diff --git a/test/stage2/test.zig b/test/cases.zig
similarity index 99%
rename from test/stage2/test.zig
rename to test/cases.zig
index a6d948fd53..7655120157 100644
--- a/test/stage2/test.zig
+++ b/test/cases.zig
@@ -1,5 +1,5 @@
const std = @import("std");
-const TestContext = @import("../../src/test.zig").TestContext;
+const TestContext = @import("../src/test.zig").TestContext;
// Self-hosted has differing levels of support for various architectures. For now we pass explicit
// target parameters to each test case. At some point we will take this to the next level and have
@@ -12,13 +12,14 @@ const linux_x64 = std.zig.CrossTarget{
};
pub fn addCases(ctx: *TestContext) !void {
- try @import("cbe.zig").addCases(ctx);
- try @import("arm.zig").addCases(ctx);
- try @import("aarch64.zig").addCases(ctx);
- try @import("llvm.zig").addCases(ctx);
- try @import("wasm.zig").addCases(ctx);
- try @import("darwin.zig").addCases(ctx);
- try @import("riscv64.zig").addCases(ctx);
+ try @import("compile_errors.zig").addCases(ctx);
+ try @import("stage2/cbe.zig").addCases(ctx);
+ try @import("stage2/arm.zig").addCases(ctx);
+ try @import("stage2/aarch64.zig").addCases(ctx);
+ try @import("stage2/llvm.zig").addCases(ctx);
+ try @import("stage2/wasm.zig").addCases(ctx);
+ try @import("stage2/darwin.zig").addCases(ctx);
+ try @import("stage2/riscv64.zig").addCases(ctx);
{
var case = ctx.exe("hello world with updates", linux_x64);
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
index 6a17551ca7..3006a6889d 100644
--- a/test/compile_errors.zig
+++ b/test/compile_errors.zig
@@ -1,53 +1,50 @@
-const tests = @import("tests.zig");
const std = @import("std");
+const TestContext = @import("../src/test.zig").TestContext;
-pub fn addCases(cases: *tests.CompileErrorContext) void {
- cases.add("std.fmt error for unused arguments",
- \\pub fn main() !void {
- \\ @import("std").debug.print("{d} {d} {d} {d} {d}", .{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15});
- \\}
- , &.{
- \\error: 10 unused arguments in "{d} {d} {d} {d} {d}"
- });
-
- cases.add("lazy pointer with undefined element type",
+pub fn addCases(ctx: *TestContext) !void {
+ ctx.objErrStage1("lazy pointer with undefined element type",
\\export fn foo() void {
\\ comptime var T: type = undefined;
\\ const S = struct { x: *T };
\\ const I = @typeInfo(S);
+ \\ _ = I;
\\}
, &[_][]const u8{
- "tmp.zig:3:28: error: use of undefined value here causes undefined behavior",
+ ":3:28: error: use of undefined value here causes undefined behavior",
});
- cases.add("pointer arithmetic on pointer-to-array",
+ ctx.objErrStage1("pointer arithmetic on pointer-to-array",
\\export fn foo() void {
\\ var x: [10]u8 = undefined;
\\ var y = &x;
\\ var z = y + 1;
+ \\ _ = z;
\\}
, &[_][]const u8{
"tmp.zig:4:17: error: integer value 1 cannot be coerced to type '*[10]u8'",
});
- cases.add("pointer attributes checked when coercing pointer to anon literal",
+ ctx.objErrStage1("pointer attributes checked when coercing pointer to anon literal",
\\comptime {
\\ const c: [][]const u8 = &.{"hello", "world" };
+ \\ _ = c;
\\}
\\comptime {
\\ const c: *[2][]const u8 = &.{"hello", "world" };
+ \\ _ = c;
\\}
\\const S = struct {a: u8 = 1, b: u32 = 2};
\\comptime {
\\ const c: *S = &.{};
+ \\ _ = c;
\\}
, &[_][]const u8{
"tmp.zig:2:31: error: expected type '[][]const u8', found '*const struct:2:31'",
- "tmp.zig:5:33: error: expected type '*[2][]const u8', found '*const struct:5:33'",
- "tmp.zig:9:21: error: expected type '*S', found '*const struct:9:21'",
+ "tmp.zig:6:33: error: expected type '*[2][]const u8', found '*const struct:6:33'",
+ "tmp.zig:11:21: error: expected type '*S', found '*const struct:11:21'",
});
- cases.add("@Type() union payload is undefined",
+ ctx.objErrStage1("@Type() union payload is undefined",
\\const Foo = @Type(@import("std").builtin.TypeInfo{
\\ .Struct = undefined,
\\});
@@ -56,7 +53,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:1:50: error: use of undefined value here causes undefined behavior",
});
- cases.add("wrong initializer for union payload of type 'type'",
+ ctx.objErrStage1("wrong initializer for union payload of type 'type'",
\\const U = union(enum) {
\\ A: type,
\\};
@@ -71,7 +68,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:9:8: error: use of undefined value here causes undefined behavior",
});
- cases.add("union with too small explicit signed tag type",
+ ctx.objErrStage1("union with too small explicit signed tag type",
\\const U = union(enum(i2)) {
\\ A: u8,
\\ B: u8,
@@ -86,7 +83,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:1:22: note: type i2 cannot fit values in range 0...3",
});
- cases.add("union with too small explicit unsigned tag type",
+ ctx.objErrStage1("union with too small explicit unsigned tag type",
\\const U = union(enum(u2)) {
\\ A: u8,
\\ B: u8,
@@ -102,56 +99,60 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:1:22: note: type u2 cannot fit values in range 0...4",
});
- cases.addCase(x: {
- var tc = cases.create("callconv(.Interrupt) on unsupported platform",
+ {
+ const case = ctx.obj("callconv(.Interrupt) on unsupported platform", .{
+ .cpu_arch = .aarch64,
+ .os_tag = .linux,
+ .abi = .none,
+ });
+ case.backend = .stage1;
+ case.addError(
\\export fn entry() callconv(.Interrupt) void {}
, &[_][]const u8{
"tmp.zig:1:28: error: callconv 'Interrupt' is only available on x86, x86_64, AVR, and MSP430, not aarch64",
});
- tc.target = std.zig.CrossTarget{
- .cpu_arch = .aarch64,
+ }
+ {
+ var case = ctx.obj("callconv(.Signal) on unsupported platform", .{
+ .cpu_arch = .x86_64,
.os_tag = .linux,
.abi = .none,
- };
- break :x tc;
- });
-
- cases.addCase(x: {
- var tc = cases.create("callconv(.Signal) on unsupported platform",
+ });
+ case.backend = .stage1;
+ case.addError(
\\export fn entry() callconv(.Signal) void {}
, &[_][]const u8{
"tmp.zig:1:28: error: callconv 'Signal' is only available on AVR, not x86_64",
});
- tc.target = std.zig.CrossTarget{
+ }
+ {
+ const case = ctx.obj("callconv(.Stdcall, .Fastcall, .Thiscall) on unsupported platform", .{
.cpu_arch = .x86_64,
.os_tag = .linux,
.abi = .none,
- };
- break :x tc;
- });
- cases.addCase(x: {
- var tc = cases.create("callconv(.Stdcall, .Fastcall, .Thiscall) on unsupported platform",
+ });
+ case.backend = .stage1;
+ case.addError(
\\const F1 = fn () callconv(.Stdcall) void;
\\const F2 = fn () callconv(.Fastcall) void;
\\const F3 = fn () callconv(.Thiscall) void;
- \\export fn entry1() void { var a: F1 = undefined; }
- \\export fn entry2() void { var a: F2 = undefined; }
- \\export fn entry3() void { var a: F3 = undefined; }
+ \\export fn entry1() void { var a: F1 = undefined; _ = a; }
+ \\export fn entry2() void { var a: F2 = undefined; _ = a; }
+ \\export fn entry3() void { var a: F3 = undefined; _ = a; }
, &[_][]const u8{
"tmp.zig:1:27: error: callconv 'Stdcall' is only available on x86, not x86_64",
"tmp.zig:2:27: error: callconv 'Fastcall' is only available on x86, not x86_64",
"tmp.zig:3:27: error: callconv 'Thiscall' is only available on x86, not x86_64",
});
- tc.target = std.zig.CrossTarget{
+ }
+ {
+ const case = ctx.obj("callconv(.Stdcall, .Fastcall, .Thiscall) on unsupported platform", .{
.cpu_arch = .x86_64,
.os_tag = .linux,
.abi = .none,
- };
- break :x tc;
- });
-
- cases.addCase(x: {
- var tc = cases.create("callconv(.Stdcall, .Fastcall, .Thiscall) on unsupported platform",
+ });
+ case.backend = .stage1;
+ case.addError(
\\export fn entry1() callconv(.Stdcall) void {}
\\export fn entry2() callconv(.Fastcall) void {}
\\export fn entry3() callconv(.Thiscall) void {}
@@ -160,30 +161,28 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:29: error: callconv 'Fastcall' is only available on x86, not x86_64",
"tmp.zig:3:29: error: callconv 'Thiscall' is only available on x86, not x86_64",
});
- tc.target = std.zig.CrossTarget{
+ }
+ {
+ const case = ctx.obj("callconv(.Vectorcall) on unsupported platform", .{
.cpu_arch = .x86_64,
.os_tag = .linux,
.abi = .none,
- };
- break :x tc;
- });
-
- cases.addCase(x: {
- var tc = cases.create("callconv(.Vectorcall) on unsupported platform",
+ });
+ case.backend = .stage1;
+ case.addError(
\\export fn entry() callconv(.Vectorcall) void {}
, &[_][]const u8{
"tmp.zig:1:28: error: callconv 'Vectorcall' is only available on x86 and AArch64, not x86_64",
});
- tc.target = std.zig.CrossTarget{
+ }
+ {
+ const case = ctx.obj("callconv(.APCS, .AAPCS, .AAPCSVFP) on unsupported platform", .{
.cpu_arch = .x86_64,
.os_tag = .linux,
.abi = .none,
- };
- break :x tc;
- });
-
- cases.addCase(x: {
- var tc = cases.create("callconv(.APCS, .AAPCS, .AAPCSVFP) on unsupported platform",
+ });
+ case.backend = .stage1;
+ case.addError(
\\export fn entry1() callconv(.APCS) void {}
\\export fn entry2() callconv(.AAPCS) void {}
\\export fn entry3() callconv(.AAPCSVFP) void {}
@@ -192,15 +191,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:29: error: callconv 'AAPCS' is only available on ARM, not x86_64",
"tmp.zig:3:29: error: callconv 'AAPCSVFP' is only available on ARM, not x86_64",
});
- tc.target = std.zig.CrossTarget{
- .cpu_arch = .x86_64,
- .os_tag = .linux,
- .abi = .none,
- };
- break :x tc;
- });
+ }
- cases.add("unreachable executed at comptime",
+ ctx.objErrStage1("unreachable executed at comptime",
\\fn foo(comptime x: i32) i32 {
\\ comptime {
\\ if (x >= 0) return -x;
@@ -215,7 +208,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:8:12: note: called from here",
});
- cases.add("@Type with TypeInfo.Int",
+ ctx.objErrStage1("@Type with TypeInfo.Int",
\\const builtin = @import("std").builtin;
\\export fn entry() void {
\\ _ = @Type(builtin.TypeInfo.Int {
@@ -227,7 +220,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:36: error: expected type 'std.builtin.TypeInfo', found 'std.builtin.Int'",
});
- cases.add("indexing a undefined slice at comptime",
+ ctx.objErrStage1("indexing a undefined slice at comptime",
\\comptime {
\\ var slice: []u8 = undefined;
\\ slice[0] = 2;
@@ -236,7 +229,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:10: error: index 0 outside slice of size 0",
});
- cases.add("array in c exported function",
+ ctx.objErrStage1("array in c exported function",
\\export fn zig_array(x: [10]u8) void {
\\try expect(std.mem.eql(u8, &x, "1234567890"));
\\}
@@ -249,7 +242,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:5:30: error: return type '[10]u8' not allowed in function with calling convention 'C'",
});
- cases.add("@Type for exhaustive enum with undefined tag type",
+ ctx.objErrStage1("@Type for exhaustive enum with undefined tag type",
\\const TypeInfo = @import("std").builtin.TypeInfo;
\\const Tag = @Type(.{
\\ .Enum = .{
@@ -267,19 +260,20 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:20: error: use of undefined value here causes undefined behavior",
});
- cases.add("extern struct with non-extern-compatible integer tag type",
+ ctx.objErrStage1("extern struct with non-extern-compatible integer tag type",
\\pub const E = enum(u31) { A, B, C };
\\pub const S = extern struct {
\\ e: E,
\\};
\\export fn entry() void {
\\ const s: S = undefined;
+ \\ _ = s;
\\}
, &[_][]const u8{
"tmp.zig:3:5: error: extern structs cannot contain fields of type 'E'",
});
- cases.add("@Type for exhaustive enum with non-integer tag type",
+ ctx.objErrStage1("@Type for exhaustive enum with non-integer tag type",
\\const TypeInfo = @import("std").builtin.TypeInfo;
\\const Tag = @Type(.{
\\ .Enum = .{
@@ -297,7 +291,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:20: error: TypeInfo.Enum.tag_type must be an integer type, not 'bool'",
});
- cases.add("extern struct with extern-compatible but inferred integer tag type",
+ ctx.objErrStage1("extern struct with extern-compatible but inferred integer tag type",
\\pub const E = enum {
\\@"0",@"1",@"2",@"3",@"4",@"5",@"6",@"7",@"8",@"9",@"10",@"11",@"12",
\\@"13",@"14",@"15",@"16",@"17",@"18",@"19",@"20",@"21",@"22",@"23",
@@ -333,12 +327,13 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\export fn entry() void {
\\ if (@typeInfo(E).Enum.tag_type != u8) @compileError("did not infer u8 tag type");
\\ const s: S = undefined;
+ \\ _ = s;
\\}
, &[_][]const u8{
"tmp.zig:31:5: error: extern structs cannot contain fields of type 'E'",
});
- cases.add("@Type for tagged union with extra enum field",
+ ctx.objErrStage1("@Type for tagged union with extra enum field",
\\const TypeInfo = @import("std").builtin.TypeInfo;
\\const Tag = @Type(.{
\\ .Enum = .{
@@ -373,7 +368,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:27:24: note: referenced here",
});
- cases.add("field access of opaque type",
+ ctx.objErrStage1("field access of opaque type",
\\const MyType = opaque {};
\\
\\export fn entry() bool {
@@ -388,16 +383,17 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:9:13: error: no member named 'blah' in opaque type 'MyType'",
});
- cases.add("opaque type with field",
+ ctx.objErrStage1("opaque type with field",
\\const Opaque = opaque { foo: i32 };
\\export fn entry() void {
\\ const foo: ?*Opaque = null;
+ \\ _ = foo;
\\}
, &[_][]const u8{
"tmp.zig:1:25: error: opaque types cannot have fields",
});
- cases.add("@Type(.Fn) with is_generic = true",
+ ctx.objErrStage1("@Type(.Fn) with is_generic = true",
\\const Foo = @Type(.{
\\ .Fn = .{
\\ .calling_convention = .Unspecified,
@@ -413,7 +409,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:1:20: error: TypeInfo.Fn.is_generic must be false for @Type",
});
- cases.add("@Type(.Fn) with is_var_args = true and non-C callconv",
+ ctx.objErrStage1("@Type(.Fn) with is_var_args = true and non-C callconv",
\\const Foo = @Type(.{
\\ .Fn = .{
\\ .calling_convention = .Unspecified,
@@ -429,7 +425,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:1:20: error: varargs functions must have C calling convention",
});
- cases.add("@Type(.Fn) with return_type = null",
+ ctx.objErrStage1("@Type(.Fn) with return_type = null",
\\const Foo = @Type(.{
\\ .Fn = .{
\\ .calling_convention = .Unspecified,
@@ -445,7 +441,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:1:20: error: TypeInfo.Fn.return_type must be non-null for @Type",
});
- cases.add("@Type for union with opaque field",
+ ctx.objErrStage1("@Type for union with opaque field",
\\const TypeInfo = @import("std").builtin.TypeInfo;
\\const Untagged = @Type(.{
\\ .Union = .{
@@ -465,23 +461,25 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:13:17: note: referenced here",
});
- cases.add("slice sentinel mismatch",
+ ctx.objErrStage1("slice sentinel mismatch",
\\export fn entry() void {
\\ const x = @import("std").meta.Vector(3, f32){ 25, 75, 5, 0 };
+ \\ _ = x;
\\}
, &[_][]const u8{
"tmp.zig:2:62: error: index 3 outside vector of size 3",
});
- cases.add("slice sentinel mismatch",
+ ctx.objErrStage1("slice sentinel mismatch",
\\export fn entry() void {
\\ const y: [:1]const u8 = &[_:2]u8{ 1, 2 };
+ \\ _ = y;
\\}
, &[_][]const u8{
"tmp.zig:2:37: error: expected type '[:1]const u8', found '*const [2:2]u8'",
});
- cases.add("@Type for union with zero fields",
+ ctx.objErrStage1("@Type for union with zero fields",
\\const TypeInfo = @import("std").builtin.TypeInfo;
\\const Untagged = @Type(.{
\\ .Union = .{
@@ -499,7 +497,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:11:17: note: referenced here",
});
- cases.add("@Type for exhaustive enum with zero fields",
+ ctx.objErrStage1("@Type for exhaustive enum with zero fields",
\\const TypeInfo = @import("std").builtin.TypeInfo;
\\const Tag = @Type(.{
\\ .Enum = .{
@@ -518,7 +516,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:12:9: note: referenced here",
});
- cases.add("@Type for tagged union with extra union field",
+ ctx.objErrStage1("@Type for tagged union with extra union field",
\\const TypeInfo = @import("std").builtin.TypeInfo;
\\const Tag = @Type(.{
\\ .Enum = .{
@@ -554,7 +552,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:27:24: note: referenced here",
});
- cases.add("@Type with undefined",
+ ctx.objErrStage1("@Type with undefined",
\\comptime {
\\ _ = @Type(.{ .Array = .{ .len = 0, .child = u8, .sentinel = undefined } });
\\}
@@ -573,7 +571,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:5:16: error: use of undefined value here causes undefined behavior",
});
- cases.add("struct with declarations unavailable for @Type",
+ ctx.objErrStage1("struct with declarations unavailable for @Type",
\\export fn entry() void {
\\ _ = @Type(@typeInfo(struct { const foo = 1; }));
\\}
@@ -581,7 +579,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:15: error: TypeInfo.Struct.decls must be empty for @Type",
});
- cases.add("enum with declarations unavailable for @Type",
+ ctx.objErrStage1("enum with declarations unavailable for @Type",
\\export fn entry() void {
\\ _ = @Type(@typeInfo(enum { foo, const bar = 1; }));
\\}
@@ -589,36 +587,44 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:15: error: TypeInfo.Enum.decls must be empty for @Type",
});
- cases.addTest("reject extern variables with initializers",
+ ctx.testErrStage1("reject extern variables with initializers",
\\extern var foo: int = 2;
, &[_][]const u8{
- "tmp.zig:1:1: error: extern variables have no initializers",
+ "tmp.zig:1:23: error: extern variables have no initializers",
});
- cases.addTest("duplicate/unused labels",
+ ctx.testErrStage1("duplicate/unused labels",
\\comptime {
\\ blk: { blk: while (false) {} }
+ \\}
+ \\comptime {
\\ blk: while (false) { blk: for (@as([0]void, undefined)) |_| {} }
+ \\}
+ \\comptime {
\\ blk: for (@as([0]void, undefined)) |_| { blk: {} }
\\}
\\comptime {
\\ blk: {}
+ \\}
+ \\comptime {
\\ blk: while(false) {}
+ \\}
+ \\comptime {
\\ blk: for(@as([0]void, undefined)) |_| {}
\\}
, &[_][]const u8{
- "tmp.zig:2:17: error: redeclaration of label 'blk'",
- "tmp.zig:2:10: note: previous declaration is here",
- "tmp.zig:3:31: error: redeclaration of label 'blk'",
- "tmp.zig:3:10: note: previous declaration is here",
- "tmp.zig:4:51: error: redeclaration of label 'blk'",
- "tmp.zig:4:10: note: previous declaration is here",
- "tmp.zig:7:10: error: unused block label",
- "tmp.zig:8:10: error: unused while label",
- "tmp.zig:9:10: error: unused for label",
+ "tmp.zig:2:12: error: redefinition of label 'blk'",
+ "tmp.zig:2:5: note: previous definition is here",
+ "tmp.zig:5:26: error: redefinition of label 'blk'",
+ "tmp.zig:5:5: note: previous definition is here",
+ "tmp.zig:8:46: error: redefinition of label 'blk'",
+ "tmp.zig:8:5: note: previous definition is here",
+ "tmp.zig:11:5: error: unused block label",
+ "tmp.zig:14:5: error: unused while loop label",
+ "tmp.zig:17:5: error: unused for loop label",
});
- cases.addTest("@alignCast of zero sized types",
+ ctx.testErrStage1("@alignCast of zero sized types",
\\export fn foo() void {
\\ const a: *void = undefined;
\\ _ = @alignCast(2, a);
@@ -633,7 +639,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
\\export fn qux() void {
\\ const a = struct {
- \\ fn a(comptime b: u32) void {}
+ \\ fn a(comptime b: u32) void { _ = b; }
\\ }.a;
\\ _ = @alignCast(2, a);
\\}
@@ -644,7 +650,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:17:23: error: cannot adjust alignment of zero sized type 'fn(u32) anytype'",
});
- cases.addTest("invalid non-exhaustive enum to union",
+ ctx.testErrStage1("invalid non-exhaustive enum to union",
\\const E = enum(u8) {
\\ a,
\\ b,
@@ -657,17 +663,19 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\export fn foo() void {
\\ var e = @intToEnum(E, 15);
\\ var u: U = e;
+ \\ _ = u;
\\}
\\export fn bar() void {
\\ const e = @intToEnum(E, 15);
\\ var u: U = e;
+ \\ _ = u;
\\}
, &[_][]const u8{
"tmp.zig:12:16: error: runtime cast to union 'U' from non-exhustive enum",
- "tmp.zig:16:16: error: no tag by value 15",
+ "tmp.zig:17:16: error: no tag by value 15",
});
- cases.addTest("switching with exhaustive enum has '_' prong ",
+ ctx.testErrStage1("switching with exhaustive enum has '_' prong ",
\\const E = enum{
\\ a,
\\ b,
@@ -684,7 +692,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:7:5: error: switch on exhaustive enum has `_` prong",
});
- cases.addTest("invalid pointer with @Type",
+ ctx.testErrStage1("invalid pointer with @Type",
\\export fn entry() void {
\\ _ = @Type(.{ .Pointer = .{
\\ .size = .One,
@@ -700,7 +708,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:16: error: sentinels are only allowed on slices and unknown-length pointers",
});
- cases.addTest("helpful return type error message",
+ ctx.testErrStage1("helpful return type error message",
\\export fn foo() u32 {
\\ return error.Ohno;
\\}
@@ -728,7 +736,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:14:5: note: cannot store an error in type 'u32'",
});
- cases.addTest("int/float conversion to comptime_int/float",
+ ctx.testErrStage1("int/float conversion to comptime_int/float",
\\export fn foo() void {
\\ var a: f32 = 2;
\\ _ = @floatToInt(comptime_int, a);
@@ -744,16 +752,16 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:7:9: note: referenced here",
});
- cases.add("extern variable has no type",
+ ctx.objErrStage1("extern variable has no type",
\\extern var foo;
\\pub export fn entry() void {
\\ foo;
\\}
, &[_][]const u8{
- "tmp.zig:1:1: error: unable to infer variable type",
+ "tmp.zig:1:8: error: unable to infer variable type",
});
- cases.add("@src outside function",
+ ctx.objErrStage1("@src outside function",
\\comptime {
\\ @src();
\\}
@@ -761,7 +769,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:5: error: @src outside function",
});
- cases.add("call assigned to constant",
+ ctx.objErrStage1("call assigned to constant",
\\const Foo = struct {
\\ x: i32,
\\};
@@ -784,15 +792,15 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:16:14: error: cannot assign to constant",
});
- cases.add("invalid pointer syntax",
+ ctx.objErrStage1("invalid pointer syntax",
\\export fn foo() void {
\\ var guid: *:0 const u8 = undefined;
\\}
, &[_][]const u8{
- "tmp.zig:2:15: error: sentinels are only allowed on unknown-length pointers",
+ "tmp.zig:2:16: error: expected type expression, found ':'",
});
- cases.add("declaration between fields",
+ ctx.objErrStage1("declaration between fields",
\\const S = struct {
\\ const foo = 2;
\\ const bar = 2;
@@ -810,16 +818,16 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:6:5: error: declarations are not allowed between container fields",
});
- cases.add("non-extern function with var args",
+ ctx.objErrStage1("non-extern function with var args",
\\fn foo(args: ...) void {}
\\export fn entry() void {
\\ foo();
\\}
, &[_][]const u8{
- "tmp.zig:1:1: error: non-extern function is variadic",
+ "tmp.zig:1:14: error: expected type expression, found '...'",
});
- cases.addTest("invalid int casts",
+ ctx.testErrStage1("invalid int casts",
\\export fn foo() void {
\\ var a: u32 = 2;
\\ _ = @intCast(comptime_int, a);
@@ -847,7 +855,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:15:9: note: referenced here",
});
- cases.addTest("invalid float casts",
+ ctx.testErrStage1("invalid float casts",
\\export fn foo() void {
\\ var a: f32 = 2;
\\ _ = @floatCast(comptime_float, a);
@@ -875,7 +883,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:15:9: note: referenced here",
});
- cases.addTest("invalid assignments",
+ ctx.testErrStage1("invalid assignments",
\\export fn entry1() void {
\\ var a: []const u8 = "foo";
\\ a[0..2] = "bar";
@@ -893,7 +901,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:10:7: error: invalid left-hand side to assignment",
});
- cases.addTest("reassign to array parameter",
+ ctx.testErrStage1("reassign to array parameter",
\\fn reassign(a: [3]f32) void {
\\ a = [3]f32{4, 5, 6};
\\}
@@ -904,7 +912,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:15: error: cannot assign to constant",
});
- cases.addTest("reassign to slice parameter",
+ ctx.testErrStage1("reassign to slice parameter",
\\pub fn reassign(s: []const u8) void {
\\ s = s[0..];
\\}
@@ -915,7 +923,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:10: error: cannot assign to constant",
});
- cases.addTest("reassign to struct parameter",
+ ctx.testErrStage1("reassign to struct parameter",
\\const S = struct {
\\ x: u32,
\\};
@@ -929,7 +937,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:5:10: error: cannot assign to constant",
});
- cases.addTest("reference to const data",
+ ctx.testErrStage1("reference to const data",
\\export fn foo() void {
\\ var ptr = &[_]u8{0,0,0,0};
\\ ptr[1] = 2;
@@ -957,7 +965,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:19:13: error: cannot assign to constant",
});
- cases.addTest("cast between ?T where T is not a pointer",
+ ctx.testErrStage1("cast between ?T where T is not a pointer",
\\pub const fnty1 = ?fn (i8) void;
\\pub const fnty2 = ?fn (u64) void;
\\export fn entry() void {
@@ -970,7 +978,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:6:9: note: optional type child 'fn(u64) void' cannot cast into optional type child 'fn(i8) void'",
});
- cases.addTest("unused variable error on errdefer",
+ ctx.testErrStage1("unused variable error on errdefer",
\\fn foo() !void {
\\ errdefer |a| unreachable;
\\ return error.A;
@@ -982,18 +990,19 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:15: error: unused variable: 'a'",
});
- cases.addTest("comparison of non-tagged union and enum literal",
+ ctx.testErrStage1("comparison of non-tagged union and enum literal",
\\export fn entry() void {
\\ const U = union { A: u32, B: u64 };
\\ var u = U{ .A = 42 };
\\ var ok = u == .A;
+ \\ _ = ok;
\\}
, &[_][]const u8{
"tmp.zig:4:16: error: comparison of union and enum literal is only valid for tagged union types",
"tmp.zig:2:15: note: type U is not a tagged union",
});
- cases.addTest("shift on type with non-power-of-two size",
+ ctx.testErrStage1("shift on type with non-power-of-two size",
\\export fn entry() void {
\\ const S = struct {
\\ fn a() void {
@@ -1025,7 +1034,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:17:17: error: RHS of shift is too large for LHS type",
});
- cases.addTest("combination of nosuspend and async",
+ ctx.testErrStage1("combination of nosuspend and async",
\\export fn entry() void {
\\ nosuspend {
\\ const bar = async foo();
@@ -1035,10 +1044,11 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
\\fn foo() void {}
, &[_][]const u8{
- "tmp.zig:4:9: error: suspend in nosuspend scope",
+ "tmp.zig:4:9: error: suspend inside nosuspend block",
+ "tmp.zig:2:5: note: nosuspend block here",
});
- cases.add("atomicrmw with bool op not .Xchg",
+ ctx.objErrStage1("atomicrmw with bool op not .Xchg",
\\export fn entry() void {
\\ var x = false;
\\ _ = @atomicRmw(bool, &x, .Add, true, .SeqCst);
@@ -1047,7 +1057,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:30: error: @atomicRmw with bool only allowed with .Xchg",
});
- cases.addTest("@TypeOf with no arguments",
+ ctx.testErrStage1("@TypeOf with no arguments",
\\export fn entry() void {
\\ _ = @TypeOf();
\\}
@@ -1055,7 +1065,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:9: error: expected at least 1 argument, found 0",
});
- cases.addTest("@TypeOf with incompatible arguments",
+ ctx.testErrStage1("@TypeOf with incompatible arguments",
\\export fn entry() void {
\\ var var_1: f32 = undefined;
\\ var var_2: u32 = undefined;
@@ -1065,7 +1075,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:4:9: error: incompatible types: 'f32' and 'u32'",
});
- cases.addTest("type mismatch with tuple concatenation",
+ ctx.testErrStage1("type mismatch with tuple concatenation",
\\export fn entry() void {
\\ var x = .{};
\\ x = x ++ .{ 1, 2, 3 };
@@ -1074,7 +1084,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:11: error: expected type 'struct:2:14', found 'struct:3:11'",
});
- cases.addTest("@tagName on invalid value of non-exhaustive enum",
+ ctx.testErrStage1("@tagName on invalid value of non-exhaustive enum",
\\test "enum" {
\\ const E = enum(u8) {A, B, _};
\\ _ = @tagName(@intToEnum(E, 5));
@@ -1083,16 +1093,17 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:18: error: no tag by value 5",
});
- cases.addTest("@ptrToInt with pointer to zero-sized type",
+ ctx.testErrStage1("@ptrToInt with pointer to zero-sized type",
\\export fn entry() void {
\\ var pointer: ?*u0 = null;
\\ var x = @ptrToInt(pointer);
+ \\ _ = x;
\\}
, &[_][]const u8{
"tmp.zig:3:23: error: pointer to size 0 type has no address",
});
- cases.addTest("access invalid @typeInfo decl",
+ ctx.testErrStage1("access invalid @typeInfo decl",
\\const A = B;
\\test "Crash" {
\\ _ = @typeInfo(@This()).Struct.decls[0];
@@ -1101,7 +1112,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:1:11: error: use of undeclared identifier 'B'",
});
- cases.addTest("reject extern function definitions with body",
+ ctx.testErrStage1("reject extern function definitions with body",
\\extern "c" fn definitelyNotInLibC(a: i32, b: i32) i32 {
\\ return a + b;
\\}
@@ -1109,7 +1120,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:1:1: error: extern functions have no body",
});
- cases.addTest("duplicate field in anonymous struct literal",
+ ctx.testErrStage1("duplicate field in anonymous struct literal",
\\export fn entry() void {
\\ const anon = .{
\\ .inner = .{
@@ -1119,31 +1130,33 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ .a = .{},
\\ },
\\ };
+ \\ _ = anon;
\\}
, &[_][]const u8{
"tmp.zig:7:13: error: duplicate field",
"tmp.zig:4:13: note: other field here",
});
- cases.addTest("type mismatch in C prototype with varargs",
+ ctx.testErrStage1("type mismatch in C prototype with varargs",
\\const fn_ty = ?fn ([*c]u8, ...) callconv(.C) void;
\\extern fn fn_decl(fmt: [*:0]u8, ...) void;
\\
\\export fn main() void {
\\ const x: fn_ty = fn_decl;
+ \\ _ = x;
\\}
, &[_][]const u8{
"tmp.zig:5:22: error: expected type 'fn([*c]u8, ...) callconv(.C) void', found 'fn([*:0]u8, ...) callconv(.C) void'",
});
- cases.addTest("dependency loop in top-level decl with @TypeInfo when accessing the decls",
+ ctx.testErrStage1("dependency loop in top-level decl with @TypeInfo when accessing the decls",
\\export const foo = @typeInfo(@This()).Struct.decls;
, &[_][]const u8{
"tmp.zig:1:20: error: dependency loop detected",
"tmp.zig:1:45: note: referenced here",
});
- cases.add("function call assigned to incorrect type",
+ ctx.objErrStage1("function call assigned to incorrect type",
\\export fn entry() void {
\\ var arr: [4]f32 = undefined;
\\ arr = concat();
@@ -1155,7 +1168,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:17: error: expected type '[4]f32', found '[16]f32'",
});
- cases.add("generic function call assigned to incorrect type",
+ ctx.objErrStage1("generic function call assigned to incorrect type",
\\pub export fn entry() void {
\\ var res: []i32 = undefined;
\\ res = myAlloc(i32);
@@ -1167,12 +1180,25 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:18: error: expected type '[]i32', found 'anyerror!i32",
});
- cases.addTest("non-exhaustive enums",
+ ctx.testErrStage1("non-exhaustive enum marker assigned a value",
\\const A = enum {
\\ a,
\\ b,
\\ _ = 1,
\\};
+ \\const B = enum {
+ \\ a,
+ \\ b,
+ \\ _,
+ \\};
+ \\comptime { _ = A; _ = B; }
+ , &[_][]const u8{
+ "tmp.zig:4:9: error: '_' is used to mark an enum as non-exhaustive and cannot be assigned a value",
+ "tmp.zig:6:11: error: non-exhaustive enum missing integer tag type",
+ "tmp.zig:9:5: note: marked non-exhaustive here",
+ });
+
+ ctx.testErrStage1("non-exhaustive enums",
\\const B = enum(u1) {
\\ a,
\\ _,
@@ -1184,18 +1210,15 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _,
\\};
\\pub export fn entry() void {
- \\ _ = A;
\\ _ = B;
\\ _ = C;
\\}
, &[_][]const u8{
- "tmp.zig:4:5: error: value assigned to '_' field of non-exhaustive enum",
- "error: non-exhaustive enum must specify size",
- "error: non-exhaustive enum specifies every value",
- "error: '_' field of non-exhaustive enum must be last",
+ "tmp.zig:3:5: error: '_' field of non-exhaustive enum must be last",
+ "tmp.zig:6:11: error: non-exhaustive enum specifies every value",
});
- cases.addTest("switching with non-exhaustive enums",
+ ctx.testErrStage1("switching with non-exhaustive enums",
\\const E = enum(u8) {
\\ a,
\\ b,
@@ -1228,7 +1251,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:21:5: error: `_` prong not allowed when switching on tagged union",
});
- cases.add("switch expression - unreachable else prong (bool)",
+ ctx.objErrStage1("switch expression - unreachable else prong (bool)",
\\fn foo(x: bool) void {
\\ switch (x) {
\\ true => {},
@@ -1241,7 +1264,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:5:9: error: unreachable else prong, all cases already handled",
});
- cases.add("switch expression - unreachable else prong (u1)",
+ ctx.objErrStage1("switch expression - unreachable else prong (u1)",
\\fn foo(x: u1) void {
\\ switch (x) {
\\ 0 => {},
@@ -1254,7 +1277,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:5:9: error: unreachable else prong, all cases already handled",
});
- cases.add("switch expression - unreachable else prong (u2)",
+ ctx.objErrStage1("switch expression - unreachable else prong (u2)",
\\fn foo(x: u2) void {
\\ switch (x) {
\\ 0 => {},
@@ -1269,7 +1292,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:7:9: error: unreachable else prong, all cases already handled",
});
- cases.add("switch expression - unreachable else prong (range u8)",
+ ctx.objErrStage1("switch expression - unreachable else prong (range u8)",
\\fn foo(x: u8) void {
\\ switch (x) {
\\ 0 => {},
@@ -1285,7 +1308,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:8:9: error: unreachable else prong, all cases already handled",
});
- cases.add("switch expression - unreachable else prong (range i8)",
+ ctx.objErrStage1("switch expression - unreachable else prong (range i8)",
\\fn foo(x: i8) void {
\\ switch (x) {
\\ -128...0 => {},
@@ -1301,7 +1324,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:8:9: error: unreachable else prong, all cases already handled",
});
- cases.add("switch expression - unreachable else prong (enum)",
+ ctx.objErrStage1("switch expression - unreachable else prong (enum)",
\\const TestEnum = enum{ T1, T2 };
\\
\\fn err(x: u8) TestEnum {
@@ -1324,7 +1347,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:14:9: error: unreachable else prong, all cases already handled",
});
- cases.addTest("@export with empty name string",
+ ctx.testErrStage1("@export with empty name string",
\\pub export fn entry() void { }
\\comptime {
\\ @export(entry, .{ .name = "" });
@@ -1333,7 +1356,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:5: error: exported symbol name cannot be empty",
});
- cases.addTest("switch ranges endpoints are validated",
+ ctx.testErrStage1("switch ranges endpoints are validated",
\\pub export fn entry() void {
\\ var x: i32 = 0;
\\ switch (x) {
@@ -1347,16 +1370,16 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:5:9: error: range start value is greater than the end value",
});
- cases.addTest("errors in for loop bodies are propagated",
+ ctx.testErrStage1("errors in for loop bodies are propagated",
\\pub export fn entry() void {
\\ var arr: [100]u8 = undefined;
\\ for (arr) |bits| _ = @popCount(bits);
\\}
, &[_][]const u8{
- "tmp.zig:3:26: error: expected 2 argument(s), found 1",
+ "tmp.zig:3:26: error: expected 2 arguments, found 1",
});
- cases.addTest("@call rejects non comptime-known fn - always_inline",
+ ctx.testErrStage1("@call rejects non comptime-known fn - always_inline",
\\pub export fn entry() void {
\\ var call_me: fn () void = undefined;
\\ @call(.{ .modifier = .always_inline }, call_me, .{});
@@ -1365,7 +1388,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:5: error: the specified modifier requires a comptime-known function",
});
- cases.addTest("@call rejects non comptime-known fn - compile_time",
+ ctx.testErrStage1("@call rejects non comptime-known fn - compile_time",
\\pub export fn entry() void {
\\ var call_me: fn () void = undefined;
\\ @call(.{ .modifier = .compile_time }, call_me, .{});
@@ -1374,19 +1397,20 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:5: error: the specified modifier requires a comptime-known function",
});
- cases.addTest("error in struct initializer doesn't crash the compiler",
+ ctx.testErrStage1("error in struct initializer doesn't crash the compiler",
\\pub export fn entry() void {
\\ const bitfield = struct {
\\ e: u8,
\\ e: u8,
\\ };
\\ var a = .{@sizeOf(bitfield)};
+ \\ _ = a;
\\}
, &[_][]const u8{
"tmp.zig:4:9: error: duplicate struct field: 'e'",
});
- cases.addTest("repeated invalid field access to generic function returning type crashes compiler. #2655",
+ ctx.testErrStage1("repeated invalid field access to generic function returning type crashes compiler. #2655",
\\pub fn A() type {
\\ return Q;
\\}
@@ -1398,15 +1422,16 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:12: error: use of undeclared identifier 'Q'",
});
- cases.add("bitCast to enum type",
+ ctx.objErrStage1("bitCast to enum type",
\\export fn entry() void {
\\ const y = @bitCast(enum(u32) { a, b }, @as(u32, 3));
+ \\ _ = y;
\\}
, &[_][]const u8{
"tmp.zig:2:24: error: cannot cast a value of type 'y'",
});
- cases.add("comparing against undefined produces undefined value",
+ ctx.objErrStage1("comparing against undefined produces undefined value",
\\export fn entry() void {
\\ if (2 == undefined) {}
\\}
@@ -1414,17 +1439,18 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:11: error: use of undefined value here causes undefined behavior",
});
- cases.add("comptime ptrcast of zero-sized type",
+ ctx.objErrStage1("comptime ptrcast of zero-sized type",
\\fn foo() void {
\\ const node: struct {} = undefined;
\\ const vla_ptr = @ptrCast([*]const u8, &node);
+ \\ _ = vla_ptr;
\\}
\\comptime { foo(); }
, &[_][]const u8{
"tmp.zig:3:21: error: '*const struct:2:17' and '[*]const u8' do not have the same in-memory representation",
});
- cases.add("slice sentinel mismatch",
+ ctx.objErrStage1("slice sentinel mismatch",
\\fn foo() [:0]u8 {
\\ var x: []u8 = undefined;
\\ return x;
@@ -1435,7 +1461,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:12: note: destination pointer requires a terminating '0' sentinel",
});
- cases.add("cmpxchg with float",
+ ctx.objErrStage1("cmpxchg with float",
\\export fn entry() void {
\\ var x: f32 = 0;
\\ _ = @cmpxchgWeak(f32, &x, 1, 2, .SeqCst, .SeqCst);
@@ -1444,7 +1470,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:22: error: expected bool, integer, enum or pointer type, found 'f32'",
});
- cases.add("atomicrmw with float op not .Xchg, .Add or .Sub",
+ ctx.objErrStage1("atomicrmw with float op not .Xchg, .Add or .Sub",
\\export fn entry() void {
\\ var x: f32 = 0;
\\ _ = @atomicRmw(f32, &x, .And, 2, .SeqCst);
@@ -1453,15 +1479,16 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:29: error: @atomicRmw with float only allowed with .Xchg, .Add and .Sub",
});
- cases.add("intToPtr with misaligned address",
+ ctx.objErrStage1("intToPtr with misaligned address",
\\pub fn main() void {
\\ var y = @intToPtr([*]align(4) u8, 5);
+ \\ _ = y;
\\}
, &[_][]const u8{
"tmp.zig:2:13: error: pointer type '[*]align(4) u8' requires aligned address",
});
- cases.add("invalid float literal",
+ ctx.objErrStage1("invalid float literal",
\\const std = @import("std");
\\
\\pub fn main() void {
@@ -1473,170 +1500,190 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:5:29: error: invalid token: '.'",
});
- cases.add("invalid exponent in float literal - 1",
+ ctx.objErrStage1("invalid exponent in float literal - 1",
\\fn main() void {
\\ var bad: f128 = 0x1.0p1ab1;
+ \\ _ = bad;
\\}
, &[_][]const u8{
"tmp.zig:2:28: error: invalid character: 'a'",
});
- cases.add("invalid exponent in float literal - 2",
+ ctx.objErrStage1("invalid exponent in float literal - 2",
\\fn main() void {
\\ var bad: f128 = 0x1.0p50F;
+ \\ _ = bad;
\\}
, &[_][]const u8{
"tmp.zig:2:29: error: invalid character: 'F'",
});
- cases.add("invalid underscore placement in float literal - 1",
+ ctx.objErrStage1("invalid underscore placement in float literal - 1",
\\fn main() void {
\\ var bad: f128 = 0._0;
+ \\ _ = bad;
\\}
, &[_][]const u8{
"tmp.zig:2:23: error: invalid character: '_'",
});
- cases.add("invalid underscore placement in float literal - 2",
+ ctx.objErrStage1("invalid underscore placement in float literal - 2",
\\fn main() void {
\\ var bad: f128 = 0_.0;
+ \\ _ = bad;
\\}
, &[_][]const u8{
"tmp.zig:2:23: error: invalid character: '.'",
});
- cases.add("invalid underscore placement in float literal - 3",
+ ctx.objErrStage1("invalid underscore placement in float literal - 3",
\\fn main() void {
\\ var bad: f128 = 0.0_;
+ \\ _ = bad;
\\}
, &[_][]const u8{
"tmp.zig:2:25: error: invalid character: ';'",
});
- cases.add("invalid underscore placement in float literal - 4",
+ ctx.objErrStage1("invalid underscore placement in float literal - 4",
\\fn main() void {
\\ var bad: f128 = 1.0e_1;
+ \\ _ = bad;
\\}
, &[_][]const u8{
"tmp.zig:2:25: error: invalid character: '_'",
});
- cases.add("invalid underscore placement in float literal - 5",
+ ctx.objErrStage1("invalid underscore placement in float literal - 5",
\\fn main() void {
\\ var bad: f128 = 1.0e+_1;
+ \\ _ = bad;
\\}
, &[_][]const u8{
"tmp.zig:2:26: error: invalid character: '_'",
});
- cases.add("invalid underscore placement in float literal - 6",
+ ctx.objErrStage1("invalid underscore placement in float literal - 6",
\\fn main() void {
\\ var bad: f128 = 1.0e-_1;
+ \\ _ = bad;
\\}
, &[_][]const u8{
"tmp.zig:2:26: error: invalid character: '_'",
});
- cases.add("invalid underscore placement in float literal - 7",
+ ctx.objErrStage1("invalid underscore placement in float literal - 7",
\\fn main() void {
\\ var bad: f128 = 1.0e-1_;
+ \\ _ = bad;
\\}
, &[_][]const u8{
"tmp.zig:2:28: error: invalid character: ';'",
});
- cases.add("invalid underscore placement in float literal - 9",
+ ctx.objErrStage1("invalid underscore placement in float literal - 9",
\\fn main() void {
\\ var bad: f128 = 1__0.0e-1;
+ \\ _ = bad;
\\}
, &[_][]const u8{
"tmp.zig:2:23: error: invalid character: '_'",
});
- cases.add("invalid underscore placement in float literal - 10",
+ ctx.objErrStage1("invalid underscore placement in float literal - 10",
\\fn main() void {
\\ var bad: f128 = 1.0__0e-1;
+ \\ _ = bad;
\\}
, &[_][]const u8{
"tmp.zig:2:25: error: invalid character: '_'",
});
- cases.add("invalid underscore placement in float literal - 11",
+ ctx.objErrStage1("invalid underscore placement in float literal - 11",
\\fn main() void {
\\ var bad: f128 = 1.0e-1__0;
+ \\ _ = bad;
\\}
, &[_][]const u8{
"tmp.zig:2:28: error: invalid character: '_'",
});
- cases.add("invalid underscore placement in float literal - 12",
+ ctx.objErrStage1("invalid underscore placement in float literal - 12",
\\fn main() void {
\\ var bad: f128 = 0_x0.0;
+ \\ _ = bad;
\\}
, &[_][]const u8{
"tmp.zig:2:23: error: invalid character: 'x'",
});
- cases.add("invalid underscore placement in float literal - 13",
+ ctx.objErrStage1("invalid underscore placement in float literal - 13",
\\fn main() void {
\\ var bad: f128 = 0x_0.0;
+ \\ _ = bad;
\\}
, &[_][]const u8{
"tmp.zig:2:23: error: invalid character: '_'",
});
- cases.add("invalid underscore placement in float literal - 14",
+ ctx.objErrStage1("invalid underscore placement in float literal - 14",
\\fn main() void {
\\ var bad: f128 = 0x0.0_p1;
+ \\ _ = bad;
\\}
, &[_][]const u8{
"tmp.zig:2:27: error: invalid character: 'p'",
});
- cases.add("invalid underscore placement in int literal - 1",
+ ctx.objErrStage1("invalid underscore placement in int literal - 1",
\\fn main() void {
\\ var bad: u128 = 0010_;
+ \\ _ = bad;
\\}
, &[_][]const u8{
"tmp.zig:2:26: error: invalid character: ';'",
});
- cases.add("invalid underscore placement in int literal - 2",
+ ctx.objErrStage1("invalid underscore placement in int literal - 2",
\\fn main() void {
\\ var bad: u128 = 0b0010_;
+ \\ _ = bad;
\\}
, &[_][]const u8{
"tmp.zig:2:28: error: invalid character: ';'",
});
- cases.add("invalid underscore placement in int literal - 3",
+ ctx.objErrStage1("invalid underscore placement in int literal - 3",
\\fn main() void {
\\ var bad: u128 = 0o0010_;
+ \\ _ = bad;
\\}
, &[_][]const u8{
"tmp.zig:2:28: error: invalid character: ';'",
});
- cases.add("invalid underscore placement in int literal - 4",
+ ctx.objErrStage1("invalid underscore placement in int literal - 4",
\\fn main() void {
\\ var bad: u128 = 0x0010_;
+ \\ _ = bad;
\\}
, &[_][]const u8{
"tmp.zig:2:28: error: invalid character: ';'",
});
- cases.add("comptime struct field, no init value",
+ ctx.objErrStage1("comptime struct field, no init value",
\\const Foo = struct {
\\ comptime b: i32,
\\};
\\export fn entry() void {
\\ var f: Foo = undefined;
+ \\ _ = f;
\\}
, &[_][]const u8{
- "tmp.zig:2:5: error: comptime struct field missing initialization value",
+ "tmp.zig:2:5: error: comptime field without default initialization value",
});
- cases.add("bad usage of @call",
+ ctx.objErrStage1("bad usage of @call",
\\export fn entry1() void {
\\ @call(.{}, foo, {});
\\}
@@ -1665,20 +1712,26 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:15:5: error: the specified modifier requires a comptime-known function",
});
- cases.add("exported async function",
+ ctx.objErrStage1("exported async function",
\\export fn foo() callconv(.Async) void {}
, &[_][]const u8{
"tmp.zig:1:1: error: exported function cannot be async",
});
- cases.addExe("main missing name",
+ ctx.exeErrStage1("main missing name",
\\pub fn (main) void {}
, &[_][]const u8{
"tmp.zig:1:5: error: missing function name",
});
- cases.addCase(x: {
- var tc = cases.create("call with new stack on unsupported target",
+ {
+ const case = ctx.obj("call with new stack on unsupported target", .{
+ .cpu_arch = .wasm32,
+ .os_tag = .wasi,
+ .abi = .none,
+ });
+ case.backend = .stage1;
+ case.addError(
\\var buf: [10]u8 align(16) = undefined;
\\export fn entry() void {
\\ @call(.{.stack = &buf}, foo, .{});
@@ -1687,17 +1740,11 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
, &[_][]const u8{
"tmp.zig:3:5: error: target arch 'wasm32' does not support calling with a new stack",
});
- tc.target = std.zig.CrossTarget{
- .cpu_arch = .wasm32,
- .os_tag = .wasi,
- .abi = .none,
- };
- break :x tc;
- });
+ }
// Note: One of the error messages here is backwards. It would be nice to fix, but that's not
// going to stop me from merging this branch which fixes a bunch of other stuff.
- cases.add("incompatible sentinels",
+ ctx.objErrStage1("incompatible sentinels",
\\export fn entry1(ptr: [*:255]u8) [*:0]u8 {
\\ return ptr;
\\}
@@ -1706,9 +1753,11 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
\\export fn entry3() void {
\\ var array: [2:0]u8 = [_:255]u8{1, 2};
+ \\ _ = array;
\\}
\\export fn entry4() void {
\\ var array: [2:0]u8 = [_]u8{1, 2};
+ \\ _ = array;
\\}
, &[_][]const u8{
"tmp.zig:2:12: error: expected type '[*:0]u8', found '[*:255]u8'",
@@ -1718,11 +1767,11 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:8:35: error: expected type '[2:255]u8', found '[2:0]u8'",
"tmp.zig:8:35: note: destination array requires a terminating '255' sentinel, but source array has a terminating '0' sentinel",
- "tmp.zig:11:31: error: expected type '[2:0]u8', found '[2]u8'",
- "tmp.zig:11:31: note: destination array requires a terminating '0' sentinel",
+ "tmp.zig:12:31: error: expected type '[2:0]u8', found '[2]u8'",
+ "tmp.zig:12:31: note: destination array requires a terminating '0' sentinel",
});
- cases.add("empty switch on an integer",
+ ctx.objErrStage1("empty switch on an integer",
\\export fn entry() void {
\\ var x: u32 = 0;
\\ switch(x) {}
@@ -1731,7 +1780,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:5: error: switch must handle all possibilities",
});
- cases.add("incorrect return type",
+ ctx.objErrStage1("incorrect return type",
\\ pub export fn entry() void{
\\ _ = foo();
\\ }
@@ -1751,12 +1800,13 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:8:16: error: expected type 'A', found 'B'",
});
- cases.add("regression test #2980: base type u32 is not type checked properly when assigning a value within a struct",
+ ctx.objErrStage1("regression test #2980: base type u32 is not type checked properly when assigning a value within a struct",
\\const Foo = struct {
\\ ptr: ?*usize,
\\ uval: u32,
\\};
\\fn get_uval(x: u32) !u32 {
+ \\ _ = x;
\\ return error.NotFound;
\\}
\\export fn entry() void {
@@ -1764,12 +1814,13 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ .ptr = null,
\\ .uval = get_uval(42),
\\ };
+ \\ _ = afoo;
\\}
, &[_][]const u8{
- "tmp.zig:11:25: error: expected type 'u32', found '@typeInfo(@typeInfo(@TypeOf(get_uval)).Fn.return_type.?).ErrorUnion.error_set!u32'",
+ "tmp.zig:12:25: error: expected type 'u32', found '@typeInfo(@typeInfo(@TypeOf(get_uval)).Fn.return_type.?).ErrorUnion.error_set!u32'",
});
- cases.add("assigning to struct or union fields that are not optionals with a function that returns an optional",
+ ctx.objErrStage1("assigning to struct or union fields that are not optionals with a function that returns an optional",
\\fn maybe(is: bool) ?u8 {
\\ if (is) return @as(u8, 10) else return null;
\\}
@@ -1782,12 +1833,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\export fn entry() void {
\\ var u = U{ .Ye = maybe(false) };
\\ var s = S{ .num = maybe(false) };
+ \\ _ = u;
+ \\ _ = s;
\\}
, &[_][]const u8{
"tmp.zig:11:27: error: expected type 'u8', found '?u8'",
});
- cases.add("missing result type for phi node",
+ ctx.objErrStage1("missing result type for phi node",
\\fn foo() !void {
\\ return anyerror.Foo;
\\}
@@ -1798,7 +1851,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:5:17: error: integer value 0 cannot be coerced to type 'void'",
});
- cases.add("atomicrmw with enum op not .Xchg",
+ ctx.objErrStage1("atomicrmw with enum op not .Xchg",
\\export fn entry() void {
\\ const E = enum(u8) {
\\ a,
@@ -1813,7 +1866,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:9:27: error: @atomicRmw with enum only allowed with .Xchg",
});
- cases.add("disallow coercion from non-null-terminated pointer to null-terminated pointer",
+ ctx.objErrStage1("disallow coercion from non-null-terminated pointer to null-terminated pointer",
\\extern fn puts(s: [*:0]const u8) c_int;
\\pub fn main() void {
\\ const no_zero_array = [_]u8{'h', 'e', 'l', 'l', 'o'};
@@ -1824,7 +1877,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:5:14: error: expected type '[*:0]const u8', found '[*]const u8'",
});
- cases.add("atomic orderings of atomicStore Acquire or AcqRel",
+ ctx.objErrStage1("atomic orderings of atomicStore Acquire or AcqRel",
\\export fn entry() void {
\\ var x: u32 = 0;
\\ @atomicStore(u32, &x, 1, .Acquire);
@@ -1833,7 +1886,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:30: error: @atomicStore atomic ordering must not be Acquire or AcqRel",
});
- cases.add("missing const in slice with nested array type",
+ ctx.objErrStage1("missing const in slice with nested array type",
\\const Geo3DTex2D = struct { vertices: [][2]f32 };
\\pub fn getGeo3DTex2D() Geo3DTex2D {
\\ return Geo3DTex2D{
@@ -1844,12 +1897,13 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
\\export fn entry() void {
\\ var geo_data = getGeo3DTex2D();
+ \\ _ = geo_data;
\\}
, &[_][]const u8{
"tmp.zig:4:30: error: array literal requires address-of operator to coerce to slice type '[][2]f32'",
});
- cases.add("slicing of global undefined pointer",
+ ctx.objErrStage1("slicing of global undefined pointer",
\\var buf: *[1]u8 = undefined;
\\export fn entry() void {
\\ _ = buf[0..1];
@@ -1858,18 +1912,17 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:12: error: non-zero length slice of undefined pointer",
});
- cases.add("using invalid types in function call raises an error",
+ ctx.objErrStage1("using invalid types in function call raises an error",
\\const MenuEffect = enum {};
- \\fn func(effect: MenuEffect) void {}
+ \\fn func(effect: MenuEffect) void { _ = effect; }
\\export fn entry() void {
\\ func(MenuEffect.ThisDoesNotExist);
\\}
, &[_][]const u8{
- "tmp.zig:1:20: error: enums must have 1 or more fields",
- "tmp.zig:4:20: note: referenced here",
+ "tmp.zig:1:20: error: enum declarations must have at least one tag",
});
- cases.add("store vector pointer with unknown runtime index",
+ ctx.objErrStage1("store vector pointer with unknown runtime index",
\\export fn entry() void {
\\ var v: @import("std").meta.Vector(4, i32) = [_]i32{ 1, 5, 3, undefined };
\\
@@ -1884,22 +1937,23 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:9:8: error: unable to determine vector element index of type '*align(16:0:4:?) i32",
});
- cases.add("load vector pointer with unknown runtime index",
+ ctx.objErrStage1("load vector pointer with unknown runtime index",
\\export fn entry() void {
\\ var v: @import("std").meta.Vector(4, i32) = [_]i32{ 1, 5, 3, undefined };
\\
\\ var i: u32 = 0;
\\ var x = loadv(&v[i]);
+ \\ _ = x;
\\}
\\
\\fn loadv(ptr: anytype) i32 {
\\ return ptr.*;
\\}
, &[_][]const u8{
- "tmp.zig:9:12: error: unable to determine vector element index of type '*align(16:0:4:?) i32",
+ "tmp.zig:10:12: error: unable to determine vector element index of type '*align(16:0:4:?) i32",
});
- cases.add("using an unknown len ptr type instead of array",
+ ctx.objErrStage1("using an unknown len ptr type instead of array",
\\const resolutions = [*][*]const u8{
\\ "[320 240 ]",
\\ null,
@@ -1911,7 +1965,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:1:21: error: expected array type or [_], found '[*][*]const u8'",
});
- cases.add("comparison with error union and error value",
+ ctx.objErrStage1("comparison with error union and error value",
\\export fn entry() void {
\\ var number_or_error: anyerror!i32 = error.SomethingAwful;
\\ _ = number_or_error == error.SomethingAwful;
@@ -1920,7 +1974,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:25: error: operator not allowed for type 'anyerror!i32'",
});
- cases.add("switch with overlapping case ranges",
+ ctx.objErrStage1("switch with overlapping case ranges",
\\export fn entry() void {
\\ var q: u8 = 0;
\\ switch (q) {
@@ -1932,28 +1986,29 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:5:9: error: duplicate switch value",
});
- cases.add("invalid optional type in extern struct",
+ ctx.objErrStage1("invalid optional type in extern struct",
\\const stroo = extern struct {
\\ moo: ?[*c]u8,
\\};
- \\export fn testf(fluff: *stroo) void {}
+ \\export fn testf(fluff: *stroo) void { _ = fluff; }
, &[_][]const u8{
"tmp.zig:2:5: error: extern structs cannot contain fields of type '?[*c]u8'",
});
- cases.add("attempt to negate a non-integer, non-float or non-vector type",
+ ctx.objErrStage1("attempt to negate a non-integer, non-float or non-vector type",
\\fn foo() anyerror!u32 {
\\ return 1;
\\}
\\
\\export fn entry() void {
\\ const x = -foo();
+ \\ _ = x;
\\}
, &[_][]const u8{
"tmp.zig:6:15: error: negation of type 'anyerror!u32'",
});
- cases.add("attempt to create 17 bit float type",
+ ctx.objErrStage1("attempt to create 17 bit float type",
\\const builtin = @import("std").builtin;
\\comptime {
\\ _ = @Type(builtin.TypeInfo { .Float = builtin.TypeInfo.Float { .bits = 17 } });
@@ -1962,7 +2017,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:32: error: 17-bit float unsupported",
});
- cases.add("wrong type for @Type",
+ ctx.objErrStage1("wrong type for @Type",
\\export fn entry() void {
\\ _ = @Type(0);
\\}
@@ -1970,7 +2025,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:15: error: expected type 'std.builtin.TypeInfo', found 'comptime_int'",
});
- cases.add("@Type with non-constant expression",
+ ctx.objErrStage1("@Type with non-constant expression",
\\const builtin = @import("std").builtin;
\\var globalTypeInfo : builtin.TypeInfo = undefined;
\\export fn entry() void {
@@ -1980,7 +2035,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:4:15: error: unable to evaluate constant expression",
});
- cases.add("wrong type for argument tuple to @asyncCall",
+ ctx.objErrStage1("wrong type for argument tuple to @asyncCall",
\\export fn entry1() void {
\\ var frame: @Frame(foo) = undefined;
\\ @asyncCall(&frame, {}, foo, {});
@@ -1993,7 +2048,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:33: error: expected tuple or struct, found 'void'",
});
- cases.add("wrong type for result ptr to @asyncCall",
+ ctx.objErrStage1("wrong type for result ptr to @asyncCall",
\\export fn entry() void {
\\ _ = async amain();
\\}
@@ -2008,25 +2063,27 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:6:37: error: expected type '*i32', found 'bool'",
});
- cases.add("shift amount has to be an integer type",
+ ctx.objErrStage1("shift amount has to be an integer type",
\\export fn entry() void {
\\ const x = 1 << &@as(u8, 10);
+ \\ _ = x;
\\}
, &[_][]const u8{
"tmp.zig:2:21: error: shift amount has to be an integer type, but found '*const u8'",
"tmp.zig:2:17: note: referenced here",
});
- cases.add("bit shifting only works on integer types",
+ ctx.objErrStage1("bit shifting only works on integer types",
\\export fn entry() void {
\\ const x = &@as(u8, 1) << 10;
+ \\ _ = x;
\\}
, &[_][]const u8{
"tmp.zig:2:16: error: bit shifting operation expected integer type, found '*const u8'",
"tmp.zig:2:27: note: referenced here",
});
- cases.add("struct depends on itself via optional field",
+ ctx.objErrStage1("struct depends on itself via optional field",
\\const LhsExpr = struct {
\\ rhsExpr: ?AstObject,
\\};
@@ -2036,6 +2093,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\export fn entry() void {
\\ const lhsExpr = LhsExpr{ .rhsExpr = null };
\\ const obj = AstObject{ .lhsExpr = lhsExpr };
+ \\ _ = obj;
\\}
, &[_][]const u8{
"tmp.zig:1:17: error: struct 'LhsExpr' depends on itself",
@@ -2043,51 +2101,55 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:5: note: while checking this field",
});
- cases.add("alignment of enum field specified",
+ ctx.objErrStage1("alignment of enum field specified",
\\const Number = enum {
\\ a,
\\ b align(i32),
\\};
\\export fn entry1() void {
\\ var x: Number = undefined;
+ \\ _ = x;
\\}
, &[_][]const u8{
"tmp.zig:3:13: error: structs and unions, not enums, support field alignment",
"tmp.zig:1:16: note: consider 'union(enum)' here",
});
- cases.add("bad alignment type",
+ ctx.objErrStage1("bad alignment type",
\\export fn entry1() void {
\\ var x: []align(true) i32 = undefined;
+ \\ _ = x;
\\}
\\export fn entry2() void {
\\ var x: *align(@as(f64, 12.34)) i32 = undefined;
+ \\ _ = x;
\\}
, &[_][]const u8{
"tmp.zig:2:20: error: expected type 'u29', found 'bool'",
- "tmp.zig:5:19: error: fractional component prevents float value 12.340000 from being casted to type 'u29'",
+ "tmp.zig:6:19: error: fractional component prevents float value 12.340000 from being casted to type 'u29'",
});
- cases.addCase(x: {
- var tc = cases.create("variable in inline assembly template cannot be found",
+ {
+ const case = ctx.obj("variable in inline assembly template cannot be found", .{
+ .cpu_arch = .x86_64,
+ .os_tag = .linux,
+ .abi = .gnu,
+ });
+ case.backend = .stage1;
+ case.addError(
\\export fn entry() void {
\\ var sp = asm volatile (
\\ "mov %[foo], sp"
\\ : [bar] "=r" (-> usize)
\\ );
+ \\ _ = sp;
\\}
, &[_][]const u8{
"tmp.zig:2:14: error: could not find 'foo' in the inputs or outputs",
});
- tc.target = std.zig.CrossTarget{
- .cpu_arch = .x86_64,
- .os_tag = .linux,
- .abi = .gnu,
- };
- break :x tc;
- });
+ }
- cases.add("indirect recursion of async functions detected",
+ ctx.objErrStage1("indirect recursion of async functions detected",
\\var frame: ?anyframe = null;
\\
\\export fn a() void {
@@ -2122,7 +2184,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:26:25: note: when analyzing type '@Frame(rangeSumIndirect)' here",
});
- cases.add("non-async function pointer eventually is inferred to become async",
+ ctx.objErrStage1("non-async function pointer eventually is inferred to become async",
\\export fn a() void {
\\ var non_async_fn: fn () void = undefined;
\\ non_async_fn = func;
@@ -2136,20 +2198,26 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:6:5: note: suspends here",
});
- cases.add("bad alignment in @asyncCall",
- \\export fn entry() void {
- \\ var ptr: fn () callconv(.Async) void = func;
- \\ var bytes: [64]u8 = undefined;
- \\ _ = @asyncCall(&bytes, {}, ptr, .{});
- \\}
- \\fn func() callconv(.Async) void {}
- , &[_][]const u8{
- // Split the check in two as the alignment value is target dependent.
- "tmp.zig:4:21: error: expected type '[]align(",
- ") u8', found '*[64]u8'",
- });
+ {
+ const case = ctx.obj("bad alignment in @asyncCall", .{
+ .cpu_arch = .aarch64,
+ .os_tag = .linux,
+ .abi = .none,
+ });
+ case.backend = .stage1;
+ case.addError(
+ \\export fn entry() void {
+ \\ var ptr: fn () callconv(.Async) void = func;
+ \\ var bytes: [64]u8 = undefined;
+ \\ _ = @asyncCall(&bytes, {}, ptr, .{});
+ \\}
+ \\fn func() callconv(.Async) void {}
+ , &[_][]const u8{
+ "tmp.zig:4:21: error: expected type '[]align(8) u8', found '*[64]u8'",
+ });
+ }
- cases.add("atomic orderings of fence Acquire or stricter",
+ ctx.objErrStage1("atomic orderings of fence Acquire or stricter",
\\export fn entry() void {
\\ @fence(.Monotonic);
\\}
@@ -2157,20 +2225,22 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:12: error: atomic ordering must be Acquire or stricter",
});
- cases.add("bad alignment in implicit cast from array pointer to slice",
+ ctx.objErrStage1("bad alignment in implicit cast from array pointer to slice",
\\export fn a() void {
\\ var x: [10]u8 = undefined;
\\ var y: []align(16) u8 = &x;
+ \\ _ = y;
\\}
, &[_][]const u8{
"tmp.zig:3:30: error: expected type '[]align(16) u8', found '*[10]u8'",
});
- cases.add("result location incompatibility mismatching handle_is_ptr (generic call)",
+ ctx.objErrStage1("result location incompatibility mismatching handle_is_ptr (generic call)",
\\export fn entry() void {
\\ var damn = Container{
\\ .not_optional = getOptional(i32),
\\ };
+ \\ _ = damn;
\\}
\\pub fn getOptional(comptime T: type) ?T {
\\ return 0;
@@ -2182,11 +2252,12 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:36: error: expected type 'i32', found '?i32'",
});
- cases.add("result location incompatibility mismatching handle_is_ptr",
+ ctx.objErrStage1("result location incompatibility mismatching handle_is_ptr",
\\export fn entry() void {
\\ var damn = Container{
\\ .not_optional = getOptional(),
\\ };
+ \\ _ = damn;
\\}
\\pub fn getOptional() ?i32 {
\\ return 0;
@@ -2198,7 +2269,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:36: error: expected type 'i32', found '?i32'",
});
- cases.add("const frame cast to anyframe",
+ ctx.objErrStage1("const frame cast to anyframe",
\\export fn a() void {
\\ const f = async func();
\\ resume f;
@@ -2206,6 +2277,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\export fn b() void {
\\ const f = async func();
\\ var x: anyframe = &f;
+ \\ _ = x;
\\}
\\fn func() void {
\\ suspend {}
@@ -2215,27 +2287,30 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:7:24: error: expected type 'anyframe', found '*const @Frame(func)'",
});
- cases.add("prevent bad implicit casting of anyframe types",
+ ctx.objErrStage1("prevent bad implicit casting of anyframe types",
\\export fn a() void {
\\ var x: anyframe = undefined;
\\ var y: anyframe->i32 = x;
+ \\ _ = y;
\\}
\\export fn b() void {
\\ var x: i32 = undefined;
\\ var y: anyframe->i32 = x;
+ \\ _ = y;
\\}
\\export fn c() void {
\\ var x: @Frame(func) = undefined;
\\ var y: anyframe->i32 = &x;
+ \\ _ = y;
\\}
\\fn func() void {}
, &[_][]const u8{
"tmp.zig:3:28: error: expected type 'anyframe->i32', found 'anyframe'",
- "tmp.zig:7:28: error: expected type 'anyframe->i32', found 'i32'",
- "tmp.zig:11:29: error: expected type 'anyframe->i32', found '*@Frame(func)'",
+ "tmp.zig:8:28: error: expected type 'anyframe->i32', found 'i32'",
+ "tmp.zig:13:29: error: expected type 'anyframe->i32', found '*@Frame(func)'",
});
- cases.add("wrong frame type used for async call",
+ ctx.objErrStage1("wrong frame type used for async call",
\\export fn entry() void {
\\ var frame: @Frame(foo) = undefined;
\\ frame = async bar();
@@ -2250,18 +2325,20 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:13: error: expected type '*@Frame(bar)', found '*@Frame(foo)'",
});
- cases.add("@Frame() of generic function",
+ ctx.objErrStage1("@Frame() of generic function",
\\export fn entry() void {
\\ var frame: @Frame(func) = undefined;
+ \\ _ = frame;
\\}
\\fn func(comptime T: type) void {
\\ var x: T = undefined;
+ \\ _ = x;
\\}
, &[_][]const u8{
"tmp.zig:2:16: error: @Frame() of generic function",
});
- cases.add("@frame() causes function to be async",
+ ctx.objErrStage1("@frame() causes function to be async",
\\export fn entry() void {
\\ func();
\\}
@@ -2273,10 +2350,11 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:5:9: note: @frame() causes function to be async",
});
- cases.add("invalid suspend in exported function",
+ ctx.objErrStage1("invalid suspend in exported function",
\\export fn entry() void {
\\ var frame = async func();
\\ var result = await frame;
+ \\ _ = result;
\\}
\\fn func() void {
\\ suspend {}
@@ -2286,7 +2364,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:18: note: await here is a suspend point",
});
- cases.add("async function indirectly depends on its own frame",
+ ctx.objErrStage1("async function indirectly depends on its own frame",
\\export fn entry() void {
\\ _ = async amain();
\\}
@@ -2295,6 +2373,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
\\fn other() void {
\\ var x: [@sizeOf(@Frame(amain))]u8 = undefined;
+ \\ _ = x;
\\}
, &[_][]const u8{
"tmp.zig:4:1: error: unable to determine async function frame of 'amain'",
@@ -2302,19 +2381,20 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:8:13: note: referenced here",
});
- cases.add("async function depends on its own frame",
+ ctx.objErrStage1("async function depends on its own frame",
\\export fn entry() void {
\\ _ = async amain();
\\}
\\fn amain() callconv(.Async) void {
\\ var x: [@sizeOf(@Frame(amain))]u8 = undefined;
+ \\ _ = x;
\\}
, &[_][]const u8{
"tmp.zig:4:1: error: cannot resolve '@Frame(amain)': function not fully analyzed yet",
"tmp.zig:5:13: note: referenced here",
});
- cases.add("non async function pointer passed to @asyncCall",
+ ctx.objErrStage1("non async function pointer passed to @asyncCall",
\\export fn entry() void {
\\ var ptr = afunc;
\\ var bytes: [100]u8 align(16) = undefined;
@@ -2325,7 +2405,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:4:32: error: expected async function, found 'fn() void'",
});
- cases.add("runtime-known async function called",
+ ctx.objErrStage1("runtime-known async function called",
\\export fn entry() void {
\\ _ = async amain();
\\}
@@ -2338,7 +2418,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:6:12: error: function is not comptime-known; @asyncCall required",
});
- cases.add("runtime-known function called with async keyword",
+ ctx.objErrStage1("runtime-known function called with async keyword",
\\export fn entry() void {
\\ var ptr = afunc;
\\ _ = async ptr();
@@ -2349,7 +2429,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:15: error: function is not comptime-known; @asyncCall required",
});
- cases.add("function with ccc indirectly calling async function",
+ ctx.objErrStage1("function with ccc indirectly calling async function",
\\export fn entry() void {
\\ foo();
\\}
@@ -2366,7 +2446,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:8:5: note: suspends here",
});
- cases.add("capture group on switch prong with incompatible payload types",
+ ctx.objErrStage1("capture group on switch prong with incompatible payload types",
\\const Union = union(enum) {
\\ A: usize,
\\ B: isize,
@@ -2374,7 +2454,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\comptime {
\\ var u = Union{ .A = 8 };
\\ switch (u) {
- \\ .A, .B => |e| unreachable,
+ \\ .A, .B => |e| {
+ \\ _ = e;
+ \\ unreachable;
+ \\ },
\\ }
\\}
, &[_][]const u8{
@@ -2383,7 +2466,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:8:13: note: type 'isize' here",
});
- cases.add("wrong type to @hasField",
+ ctx.objErrStage1("wrong type to @hasField",
\\export fn entry() bool {
\\ return @hasField(i32, "hi");
\\}
@@ -2391,44 +2474,49 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:22: error: type 'i32' does not support @hasField",
});
- cases.add("slice passed as array init type with elems",
+ ctx.objErrStage1("slice passed as array init type with elems",
\\export fn entry() void {
\\ const x = []u8{1, 2};
+ \\ _ = x;
\\}
, &[_][]const u8{
"tmp.zig:2:15: error: array literal requires address-of operator to coerce to slice type '[]u8'",
});
- cases.add("slice passed as array init type",
+ ctx.objErrStage1("slice passed as array init type",
\\export fn entry() void {
\\ const x = []u8{};
+ \\ _ = x;
\\}
, &[_][]const u8{
"tmp.zig:2:15: error: array literal requires address-of operator to coerce to slice type '[]u8'",
});
- cases.add("inferred array size invalid here",
+ ctx.objErrStage1("inferred array size invalid here",
\\export fn entry() void {
\\ const x = [_]u8;
+ \\ _ = x;
\\}
\\export fn entry2() void {
\\ const S = struct { a: *const [_]u8 };
\\ var a = .{ S{} };
+ \\ _ = a;
\\}
, &[_][]const u8{
- "tmp.zig:2:15: error: inferred array size invalid here",
- "tmp.zig:5:34: error: inferred array size invalid here",
+ "tmp.zig:2:16: error: unable to infer array size",
+ "tmp.zig:6:35: error: unable to infer array size",
});
- cases.add("initializing array with struct syntax",
+ ctx.objErrStage1("initializing array with struct syntax",
\\export fn entry() void {
\\ const x = [_]u8{ .y = 2 };
+ \\ _ = x;
\\}
, &[_][]const u8{
"tmp.zig:2:15: error: initializing array with struct syntax",
});
- cases.add("compile error in struct init expression",
+ ctx.objErrStage1("compile error in struct init expression",
\\const Foo = struct {
\\ a: i32 = crap,
\\ b: i32,
@@ -2437,23 +2525,25 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var x = Foo{
\\ .b = 5,
\\ };
+ \\ _ = x;
\\}
, &[_][]const u8{
"tmp.zig:2:14: error: use of undeclared identifier 'crap'",
});
- cases.add("undefined as field type is rejected",
+ ctx.objErrStage1("undefined as field type is rejected",
\\const Foo = struct {
\\ a: undefined,
\\};
\\export fn entry1() void {
\\ const foo: Foo = undefined;
+ \\ _ = foo;
\\}
, &[_][]const u8{
"tmp.zig:2:8: error: use of undefined value here causes undefined behavior",
});
- cases.add("@hasDecl with non-container",
+ ctx.objErrStage1("@hasDecl with non-container",
\\export fn entry() void {
\\ _ = @hasDecl(i32, "hi");
\\}
@@ -2461,16 +2551,17 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:18: error: expected struct, enum, or union; found 'i32'",
});
- cases.add("field access of slices",
+ ctx.objErrStage1("field access of slices",
\\export fn entry() void {
\\ var slice: []i32 = undefined;
\\ const info = @TypeOf(slice).unknown;
+ \\ _ = info;
\\}
, &[_][]const u8{
"tmp.zig:3:32: error: type 'type' does not support field access",
});
- cases.add("peer cast then implicit cast const pointer to mutable C pointer",
+ ctx.objErrStage1("peer cast then implicit cast const pointer to mutable C pointer",
\\export fn func() void {
\\ var strValue: [*c]u8 = undefined;
\\ strValue = strValue orelse "";
@@ -2480,19 +2571,20 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:32: note: cast discards const qualifier",
});
- cases.add("overflow in enum value allocation",
+ ctx.objErrStage1("overflow in enum value allocation",
\\const Moo = enum(u8) {
\\ Last = 255,
\\ Over,
\\};
\\pub fn main() void {
\\ var y = Moo.Last;
+ \\ _ = y;
\\}
, &[_][]const u8{
"tmp.zig:3:5: error: enumeration value 256 too large for type 'u8'",
});
- cases.add("attempt to cast enum literal to error",
+ ctx.objErrStage1("attempt to cast enum literal to error",
\\export fn entry() void {
\\ switch (error.Hi) {
\\ .Hi => {},
@@ -2502,7 +2594,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:9: error: expected type 'error{Hi}', found '(enum literal)'",
});
- cases.add("@sizeOf bad type",
+ ctx.objErrStage1("@sizeOf bad type",
\\export fn entry() usize {
\\ return @sizeOf(@TypeOf(null));
\\}
@@ -2510,7 +2602,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:20: error: no size available for type '(null)'",
});
- cases.add("generic function where return type is self-referenced",
+ ctx.objErrStage1("generic function where return type is self-referenced",
\\fn Foo(comptime T: type) Foo(T) {
\\ return struct{ x: T };
\\}
@@ -2518,34 +2610,37 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const t = Foo(u32) {
\\ .x = 1
\\ };
+ \\ _ = t;
\\}
, &[_][]const u8{
"tmp.zig:1:29: error: evaluation exceeded 1000 backwards branches",
"tmp.zig:5:18: note: referenced here",
});
- cases.add("@ptrToInt 0 to non optional pointer",
+ ctx.objErrStage1("@ptrToInt 0 to non optional pointer",
\\export fn entry() void {
\\ var b = @intToPtr(*i32, 0);
+ \\ _ = b;
\\}
, &[_][]const u8{
"tmp.zig:2:13: error: pointer type '*i32' does not allow address zero",
});
- cases.add("cast enum literal to enum but it doesn't match",
+ ctx.objErrStage1("cast enum literal to enum but it doesn't match",
\\const Foo = enum {
\\ a,
\\ b,
\\};
\\export fn entry() void {
\\ const x: Foo = .c;
+ \\ _ = x;
\\}
, &[_][]const u8{
"tmp.zig:6:20: error: enum 'Foo' has no field named 'c'",
"tmp.zig:1:13: note: 'Foo' declared here",
});
- cases.add("discarding error value",
+ ctx.objErrStage1("discarding error value",
\\export fn entry() void {
\\ _ = foo();
\\}
@@ -2556,7 +2651,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:12: error: error is discarded. consider using `try`, `catch`, or `if`",
});
- cases.add("volatile on global assembly",
+ ctx.objErrStage1("volatile on global assembly",
\\comptime {
\\ asm volatile ("");
\\}
@@ -2564,7 +2659,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:9: error: volatile is meaningless on global assembly",
});
- cases.add("invalid multiple dereferences",
+ ctx.objErrStage1("invalid multiple dereferences",
\\export fn a() void {
\\ var box = Box{ .field = 0 };
\\ box.*.field = 1;
@@ -2582,13 +2677,13 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:8:13: error: attempt to dereference non-pointer type 'Box'",
});
- cases.add("usingnamespace with wrong type",
+ ctx.objErrStage1("usingnamespace with wrong type",
\\usingnamespace void;
, &[_][]const u8{
"tmp.zig:1:1: error: expected struct, enum, or union; found 'void'",
});
- cases.add("ignored expression in while continuation",
+ ctx.objErrStage1("ignored expression in while continuation",
\\export fn a() void {
\\ while (true) : (bad()) {}
\\}
@@ -2609,31 +2704,31 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:10:25: error: error is ignored. consider using `try`, `catch`, or `if`",
});
- cases.add("empty while loop body",
+ ctx.objErrStage1("empty while loop body",
\\export fn a() void {
\\ while(true);
\\}
, &[_][]const u8{
- "tmp.zig:2:16: error: expected loop body, found ';'",
+ "tmp.zig:2:16: error: expected block or assignment, found ';'",
});
- cases.add("empty for loop body",
+ ctx.objErrStage1("empty for loop body",
\\export fn a() void {
\\ for(undefined) |x|;
\\}
, &[_][]const u8{
- "tmp.zig:2:23: error: expected loop body, found ';'",
+ "tmp.zig:2:23: error: expected block or assignment, found ';'",
});
- cases.add("empty if body",
+ ctx.objErrStage1("empty if body",
\\export fn a() void {
\\ if(true);
\\}
, &[_][]const u8{
- "tmp.zig:2:13: error: expected if body, found ';'",
+ "tmp.zig:2:13: error: expected block or assignment, found ';'",
});
- cases.add("import outside package path",
+ ctx.objErrStage1("import outside package path",
\\comptime{
\\ _ = @import("../a.zig");
\\}
@@ -2641,14 +2736,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:9: error: import of file outside package path: '../a.zig'",
});
- cases.add("bogus compile var",
+ ctx.objErrStage1("bogus compile var",
\\const x = @import("builtin").bogus;
\\export fn entry() usize { return @sizeOf(@TypeOf(x)); }
, &[_][]const u8{
"tmp.zig:1:29: error: container 'builtin' has no member called 'bogus'",
});
- cases.add("wrong panic signature, runtime function",
+ ctx.objErrStage1("wrong panic signature, runtime function",
\\test "" {}
\\
\\pub fn panic() void {}
@@ -2657,8 +2752,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"error: expected type 'fn([]const u8, ?*std.builtin.StackTrace) noreturn', found 'fn() void'",
});
- cases.add("wrong panic signature, generic function",
+ ctx.objErrStage1("wrong panic signature, generic function",
\\pub fn panic(comptime msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn {
+ \\ _ = msg; _ = error_return_trace;
\\ while (true) {}
\\}
, &[_][]const u8{
@@ -2666,14 +2762,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"note: only one of the functions is generic",
});
- cases.add("direct struct loop",
+ ctx.objErrStage1("direct struct loop",
\\const A = struct { a : A, };
\\export fn entry() usize { return @sizeOf(A); }
, &[_][]const u8{
"tmp.zig:1:11: error: struct 'A' depends on itself",
});
- cases.add("indirect struct loop",
+ ctx.objErrStage1("indirect struct loop",
\\const A = struct { b : B, };
\\const B = struct { c : C, };
\\const C = struct { a : A, };
@@ -2682,7 +2778,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:1:11: error: struct 'A' depends on itself",
});
- cases.add("instantiating an undefined value for an invalid struct that contains itself",
+ ctx.objErrStage1("instantiating an undefined value for an invalid struct that contains itself",
\\const Foo = struct {
\\ x: Foo,
\\};
@@ -2697,23 +2793,25 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:8:28: note: referenced here",
});
- cases.add("enum field value references enum",
- \\pub const Foo = extern enum {
+ ctx.objErrStage1("enum field value references enum",
+ \\pub const Foo = enum(c_int) {
\\ A = Foo.B,
\\ C = D,
\\};
\\export fn entry() void {
\\ var s: Foo = Foo.E;
+ \\ _ = s;
\\}
, &[_][]const u8{
"tmp.zig:1:17: error: enum 'Foo' depends on itself",
});
- cases.add("top level decl dependency loop",
+ ctx.objErrStage1("top level decl dependency loop",
\\const a : @TypeOf(b) = 0;
\\const b : @TypeOf(a) = 0;
\\export fn entry() void {
\\ const c = a + b;
+ \\ _ = c;
\\}
, &[_][]const u8{
"tmp.zig:2:19: error: dependency loop detected",
@@ -2721,7 +2819,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:4:15: note: referenced here",
});
- cases.addTest("not an enum type",
+ ctx.testErrStage1("not an enum type",
\\export fn entry() void {
\\ var self: Error = undefined;
\\ switch (self) {
@@ -2739,18 +2837,19 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:4:9: error: expected type '@typeInfo(Error).Union.tag_type.?', found 'type'",
});
- cases.addTest("binary OR operator on error sets",
+ ctx.testErrStage1("binary OR operator on error sets",
\\pub const A = error.A;
\\pub const AB = A | error.B;
\\export fn entry() void {
\\ var x: AB = undefined;
+ \\ _ = x;
\\}
, &[_][]const u8{
"tmp.zig:2:18: error: invalid operands to binary expression: 'error{A}' and 'error{B}'",
});
if (std.Target.current.os.tag == .linux) {
- cases.addTest("implicit dependency on libc",
+ ctx.testErrStage1("implicit dependency on libc",
\\extern "c" fn exit(u8) void;
\\export fn entry() void {
\\ exit(0);
@@ -2759,7 +2858,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:5: error: dependency on libc must be explicitly specified in the build command",
});
- cases.addTest("libc headers note",
+ ctx.testErrStage1("libc headers note",
\\const c = @cImport(@cInclude("stdio.h"));
\\export fn entry() void {
\\ _ = c.printf("hello, world!\n");
@@ -2770,18 +2869,19 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
});
}
- cases.addTest("comptime vector overflow shows the index",
+ ctx.testErrStage1("comptime vector overflow shows the index",
\\comptime {
\\ var a: @import("std").meta.Vector(4, u8) = [_]u8{ 1, 2, 255, 4 };
\\ var b: @import("std").meta.Vector(4, u8) = [_]u8{ 5, 6, 1, 8 };
\\ var x = a + b;
+ \\ _ = x;
\\}
, &[_][]const u8{
"tmp.zig:4:15: error: operation caused overflow",
"tmp.zig:4:15: note: when computing vector element at index 2",
});
- cases.addTest("packed struct with fields of not allowed types",
+ ctx.testErrStage1("packed struct with fields of not allowed types",
\\const A = packed struct {
\\ x: anyerror,
\\};
@@ -2805,24 +2905,31 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\};
\\export fn entry1() void {
\\ var a: A = undefined;
+ \\ _ = a;
\\}
\\export fn entry2() void {
\\ var b: B = undefined;
+ \\ _ = b;
\\}
\\export fn entry3() void {
\\ var r: C = undefined;
+ \\ _ = r;
\\}
\\export fn entry4() void {
\\ var d: D = undefined;
+ \\ _ = d;
\\}
\\export fn entry5() void {
\\ var e: E = undefined;
+ \\ _ = e;
\\}
\\export fn entry6() void {
\\ var f: F = undefined;
+ \\ _ = f;
\\}
\\export fn entry7() void {
\\ var g: G = undefined;
+ \\ _ = g;
\\}
\\const S = struct {
\\ x: i32,
@@ -2843,42 +2950,40 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:14:5: error: non-packed, non-extern struct 'U' not allowed in packed struct; no guaranteed in-memory representation",
"tmp.zig:17:5: error: type '?anyerror' not allowed in packed struct; no guaranteed in-memory representation",
"tmp.zig:20:5: error: type 'Enum' not allowed in packed struct; no guaranteed in-memory representation",
- "tmp.zig:50:14: note: enum declaration does not specify an integer tag type",
+ "tmp.zig:57:14: note: enum declaration does not specify an integer tag type",
});
- cases.addCase(x: {
- var tc = cases.create("deduplicate undeclared identifier",
- \\export fn a() void {
- \\ x += 1;
- \\}
- \\export fn b() void {
- \\ x += 1;
- \\}
- , &[_][]const u8{
- "tmp.zig:2:5: error: use of undeclared identifier 'x'",
- });
- tc.expect_exact = true;
- break :x tc;
+ ctx.objErrStage1("deduplicate undeclared identifier",
+ \\export fn a() void {
+ \\ x += 1;
+ \\}
+ \\export fn b() void {
+ \\ x += 1;
+ \\}
+ , &[_][]const u8{
+ "tmp.zig:2:5: error: use of undeclared identifier 'x'",
});
- cases.add("export generic function",
+ ctx.objErrStage1("export generic function",
\\export fn foo(num: anytype) i32 {
+ \\ _ = num;
\\ return 0;
\\}
, &[_][]const u8{
"tmp.zig:1:15: error: parameter of type 'anytype' not allowed in function with calling convention 'C'",
});
- cases.add("C pointer to c_void",
+ ctx.objErrStage1("C pointer to c_void",
\\export fn a() void {
\\ var x: *c_void = undefined;
\\ var y: [*c]c_void = x;
+ \\ _ = y;
\\}
, &[_][]const u8{
"tmp.zig:3:16: error: C pointers cannot point to opaque types",
});
- cases.add("directly embedding opaque type in struct and union",
+ ctx.objErrStage1("directly embedding opaque type in struct and union",
\\const O = opaque {};
\\const Foo = struct {
\\ o: O,
@@ -2889,74 +2994,85 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\};
\\export fn a() void {
\\ var foo: Foo = undefined;
+ \\ _ = foo;
\\}
\\export fn b() void {
\\ var bar: Bar = undefined;
+ \\ _ = bar;
\\}
\\export fn c() void {
\\ var baz: *opaque {} = undefined;
\\ const qux = .{baz.*};
+ \\ _ = qux;
\\}
, &[_][]const u8{
"tmp.zig:3:5: error: opaque types have unknown size and therefore cannot be directly embedded in structs",
"tmp.zig:7:5: error: opaque types have unknown size and therefore cannot be directly embedded in unions",
- "tmp.zig:17:22: error: opaque types have unknown size and therefore cannot be directly embedded in structs",
+ "tmp.zig:19:22: error: opaque types have unknown size and therefore cannot be directly embedded in structs",
});
- cases.add("implicit cast between C pointer and Zig pointer - bad const/align/child",
+ ctx.objErrStage1("implicit cast between C pointer and Zig pointer - bad const/align/child",
\\export fn a() void {
\\ var x: [*c]u8 = undefined;
\\ var y: *align(4) u8 = x;
+ \\ _ = y;
\\}
\\export fn b() void {
\\ var x: [*c]const u8 = undefined;
\\ var y: *u8 = x;
+ \\ _ = y;
\\}
\\export fn c() void {
\\ var x: [*c]u8 = undefined;
\\ var y: *u32 = x;
+ \\ _ = y;
\\}
\\export fn d() void {
\\ var y: *align(1) u32 = undefined;
\\ var x: [*c]u32 = y;
+ \\ _ = x;
\\}
\\export fn e() void {
\\ var y: *const u8 = undefined;
\\ var x: [*c]u8 = y;
+ \\ _ = x;
\\}
\\export fn f() void {
\\ var y: *u8 = undefined;
\\ var x: [*c]u32 = y;
+ \\ _ = x;
\\}
, &[_][]const u8{
"tmp.zig:3:27: error: cast increases pointer alignment",
- "tmp.zig:7:18: error: cast discards const qualifier",
- "tmp.zig:11:19: error: expected type '*u32', found '[*c]u8'",
- "tmp.zig:11:19: note: pointer type child 'u8' cannot cast into pointer type child 'u32'",
- "tmp.zig:15:22: error: cast increases pointer alignment",
- "tmp.zig:19:21: error: cast discards const qualifier",
- "tmp.zig:23:22: error: expected type '[*c]u32', found '*u8'",
+ "tmp.zig:8:18: error: cast discards const qualifier",
+ "tmp.zig:13:19: error: expected type '*u32', found '[*c]u8'",
+ "tmp.zig:13:19: note: pointer type child 'u8' cannot cast into pointer type child 'u32'",
+ "tmp.zig:18:22: error: cast increases pointer alignment",
+ "tmp.zig:23:21: error: cast discards const qualifier",
+ "tmp.zig:28:22: error: expected type '[*c]u32', found '*u8'",
});
- cases.add("implicit casting null c pointer to zig pointer",
+ ctx.objErrStage1("implicit casting null c pointer to zig pointer",
\\comptime {
\\ var c_ptr: [*c]u8 = 0;
\\ var zig_ptr: *u8 = c_ptr;
+ \\ _ = zig_ptr;
\\}
, &[_][]const u8{
"tmp.zig:3:24: error: null pointer casted to type '*u8'",
});
- cases.add("implicit casting undefined c pointer to zig pointer",
+ ctx.objErrStage1("implicit casting undefined c pointer to zig pointer",
\\comptime {
\\ var c_ptr: [*c]u8 = undefined;
\\ var zig_ptr: *u8 = c_ptr;
+ \\ _ = zig_ptr;
\\}
, &[_][]const u8{
"tmp.zig:3:24: error: use of undefined value here causes undefined behavior",
});
- cases.add("implicit casting C pointers which would mess up null semantics",
+ ctx.objErrStage1("implicit casting C pointers which would mess up null semantics",
\\export fn entry() void {
\\ var slice: []const u8 = "aoeu";
\\ const opt_many_ptr: [*]const u8 = slice.ptr;
@@ -2970,6 +3086,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var opt_many_ptr: [*]u8 = slice.ptr;
\\ var ptr_opt_many_ptr = &opt_many_ptr;
\\ var c_ptr: [*c][*c]const u8 = ptr_opt_many_ptr;
+ \\ _ = c_ptr;
\\}
, &[_][]const u8{
"tmp.zig:6:24: error: expected type '*const [*]const u8', found '[*c]const [*c]const u8'",
@@ -2980,47 +3097,46 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:13:35: note: mutable '[*c]const u8' allows illegal null values stored to type '[*]u8'",
});
- cases.add("implicit casting too big integers to C pointers",
+ ctx.objErrStage1("implicit casting too big integers to C pointers",
\\export fn a() void {
\\ var ptr: [*c]u8 = (1 << 64) + 1;
+ \\ _ = ptr;
\\}
\\export fn b() void {
\\ var x: u65 = 0x1234;
\\ var ptr: [*c]u8 = x;
+ \\ _ = ptr;
\\}
, &[_][]const u8{
"tmp.zig:2:33: error: integer value 18446744073709551617 cannot be coerced to type 'usize'",
- "tmp.zig:6:23: error: integer type 'u65' too big for implicit @intToPtr to type '[*c]u8'",
+ "tmp.zig:7:23: error: integer type 'u65' too big for implicit @intToPtr to type '[*c]u8'",
});
- cases.add("C pointer pointing to non C ABI compatible type or has align attr",
+ ctx.objErrStage1("C pointer pointing to non C ABI compatible type or has align attr",
\\const Foo = struct {};
\\export fn a() void {
\\ const T = [*c]Foo;
\\ var t: T = undefined;
+ \\ _ = t;
\\}
, &[_][]const u8{
"tmp.zig:3:19: 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("!@#$"); }
- \\}
- , &[_][]const u8{
- "tmp.zig:7:39: error: found compile log statement",
- });
- tc.expect_exact = true;
- break :x tc;
+ ctx.objErrStage1("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("!@#$"); }
+ \\}
+ , &[_][]const u8{
+ "tmp.zig:7:39: error: found compile log statement",
});
- cases.add("assign to invalid dereference",
+ ctx.objErrStage1("assign to invalid dereference",
\\export fn entry() void {
\\ 'a'.* = 1;
\\}
@@ -3028,54 +3144,58 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:8: error: attempt to dereference non-pointer type 'comptime_int'",
});
- cases.add("take slice of invalid dereference",
+ ctx.objErrStage1("take slice of invalid dereference",
\\export fn entry() void {
\\ const x = 'a'.*[0..];
+ \\ _ = x;
\\}
, &[_][]const u8{
"tmp.zig:2:18: error: attempt to dereference non-pointer type 'comptime_int'",
});
- cases.add("@truncate undefined value",
+ ctx.objErrStage1("@truncate undefined value",
\\export fn entry() void {
\\ var z = @truncate(u8, @as(u16, undefined));
+ \\ _ = z;
\\}
, &[_][]const u8{
"tmp.zig:2:27: error: use of undefined value here causes undefined behavior",
});
- cases.addTest("return invalid type from test",
+ ctx.testErrStage1("return invalid type from test",
\\test "example" { return 1; }
, &[_][]const u8{
"tmp.zig:1:25: error: expected type 'void', found 'comptime_int'",
});
- cases.add("threadlocal qualifier on const",
+ ctx.objErrStage1("threadlocal qualifier on const",
\\threadlocal const x: i32 = 1234;
\\export fn entry() i32 {
\\ return x;
\\}
, &[_][]const u8{
- "tmp.zig:1:13: error: threadlocal variable cannot be constant",
+ "tmp.zig:1:1: error: threadlocal variable cannot be constant",
});
- cases.add("@bitCast same size but bit count mismatch",
+ ctx.objErrStage1("@bitCast same size but bit count mismatch",
\\export fn entry(byte: u8) void {
\\ var oops = @bitCast(u7, byte);
+ \\ _ = oops;
\\}
, &[_][]const u8{
"tmp.zig:2:25: error: destination type 'u7' has 7 bits but source type 'u8' has 8 bits",
});
- cases.add("@bitCast with different sizes inside an expression",
+ ctx.objErrStage1("@bitCast with different sizes inside an expression",
\\export fn entry() void {
\\ var foo = (@bitCast(u8, @as(f32, 1.0)) == 0xf);
+ \\ _ = foo;
\\}
, &[_][]const u8{
"tmp.zig:2:25: error: destination type 'u8' has size 1 but source type 'f32' has size 4",
});
- cases.add("attempted `&&`",
+ ctx.objErrStage1("attempted `&&`",
\\export fn entry(a: bool, b: bool) i32 {
\\ if (a && b) {
\\ return 1234;
@@ -3083,10 +3203,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return 5678;
\\}
, &[_][]const u8{
- "tmp.zig:2:12: error: `&&` is invalid. Note that `and` is boolean AND",
+ "tmp.zig:2:11: error: `&&` is invalid; note that `and` is boolean AND",
});
- cases.add("attempted `||` on boolean values",
+ ctx.objErrStage1("attempted `||` on boolean values",
\\export fn entry(a: bool, b: bool) i32 {
\\ if (a || b) {
\\ return 1234;
@@ -3098,7 +3218,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:11: note: `||` merges error sets; `or` performs boolean OR",
});
- cases.add("compile log a pointer to an opaque value",
+ ctx.objErrStage1("compile log a pointer to an opaque value",
\\export fn entry() void {
\\ @compileLog(@ptrCast(*const c_void, &entry));
\\}
@@ -3106,13 +3226,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:5: error: found compile log statement",
});
- cases.add("duplicate boolean switch value",
+ ctx.objErrStage1("duplicate boolean switch value",
\\comptime {
\\ const x = switch (true) {
\\ true => false,
\\ false => true,
\\ true => false,
\\ };
+ \\ _ = x;
\\}
\\comptime {
\\ const x = switch (true) {
@@ -3120,42 +3241,46 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ true => false,
\\ false => true,
\\ };
+ \\ _ = x;
\\}
, &[_][]const u8{
"tmp.zig:5:9: error: duplicate switch value",
- "tmp.zig:12:9: error: duplicate switch value",
+ "tmp.zig:13:9: error: duplicate switch value",
});
- cases.add("missing boolean switch value",
+ ctx.objErrStage1("missing boolean switch value",
\\comptime {
\\ const x = switch (true) {
\\ true => false,
\\ };
+ \\ _ = x;
\\}
\\comptime {
\\ const x = switch (true) {
\\ false => true,
\\ };
+ \\ _ = x;
\\}
, &[_][]const u8{
"tmp.zig:2:15: error: switch must handle all possibilities",
- "tmp.zig:7:15: error: switch must handle all possibilities",
+ "tmp.zig:8:15: error: switch must handle all possibilities",
});
- cases.add("reading past end of pointer casted array",
+ ctx.objErrStage1("reading past end of pointer casted array",
\\comptime {
\\ const array: [4]u8 = "aoeu".*;
\\ const sub_array = array[1..];
\\ const int_ptr = @ptrCast(*const u24, sub_array);
\\ const deref = int_ptr.*;
+ \\ _ = deref;
\\}
, &[_][]const u8{
"tmp.zig:5:26: error: attempt to read 4 bytes from [4]u8 at index 1 which is 3 bytes",
});
- cases.add("error note for function parameter incompatibility",
- \\fn do_the_thing(func: fn (arg: i32) void) void {}
- \\fn bar(arg: bool) void {}
+ ctx.objErrStage1("error note for function parameter incompatibility",
+ \\fn do_the_thing(func: fn (arg: i32) void) void { _ = func; }
+ \\fn bar(arg: bool) void { _ = arg; }
\\export fn entry() void {
\\ do_the_thing(bar);
\\}
@@ -3163,56 +3288,63 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:4:18: error: expected type 'fn(i32) void', found 'fn(bool) void",
"tmp.zig:4:18: note: parameter 0: 'bool' cannot cast into 'i32'",
});
- cases.add("cast negative value to unsigned integer",
+ ctx.objErrStage1("cast negative value to unsigned integer",
\\comptime {
\\ const value: i32 = -1;
\\ const unsigned = @intCast(u32, value);
+ \\ _ = unsigned;
\\}
\\export fn entry1() void {
\\ const value: i32 = -1;
\\ const unsigned: u32 = value;
+ \\ _ = unsigned;
\\}
, &[_][]const u8{
"tmp.zig:3:22: error: attempt to cast negative value to unsigned integer",
- "tmp.zig:7:27: error: cannot cast negative value -1 to unsigned integer type 'u32'",
+ "tmp.zig:8:27: error: cannot cast negative value -1 to unsigned integer type 'u32'",
});
- cases.add("integer cast truncates bits",
+ ctx.objErrStage1("integer cast truncates bits",
\\export fn entry1() void {
\\ const spartan_count: u16 = 300;
\\ const byte = @intCast(u8, spartan_count);
+ \\ _ = byte;
\\}
\\export fn entry2() void {
\\ const spartan_count: u16 = 300;
\\ const byte: u8 = spartan_count;
+ \\ _ = byte;
\\}
\\export fn entry3() void {
\\ var spartan_count: u16 = 300;
\\ var byte: u8 = spartan_count;
+ \\ _ = byte;
\\}
\\export fn entry4() void {
\\ var signed: i8 = -1;
\\ var unsigned: u64 = signed;
+ \\ _ = unsigned;
\\}
, &[_][]const u8{
"tmp.zig:3:18: error: cast from 'u16' to 'u8' truncates bits",
- "tmp.zig:7:22: error: integer value 300 cannot be coerced to type 'u8'",
- "tmp.zig:11:20: error: expected type 'u8', found 'u16'",
- "tmp.zig:11:20: note: unsigned 8-bit int cannot represent all possible unsigned 16-bit values",
- "tmp.zig:15:25: error: expected type 'u64', found 'i8'",
- "tmp.zig:15:25: note: unsigned 64-bit int cannot represent all possible signed 8-bit values",
+ "tmp.zig:8:22: error: integer value 300 cannot be coerced to type 'u8'",
+ "tmp.zig:13:20: error: expected type 'u8', found 'u16'",
+ "tmp.zig:13:20: note: unsigned 8-bit int cannot represent all possible unsigned 16-bit values",
+ "tmp.zig:18:25: error: expected type 'u64', found 'i8'",
+ "tmp.zig:18:25: note: unsigned 64-bit int cannot represent all possible signed 8-bit values",
});
- cases.add("comptime implicit cast f64 to f32",
+ ctx.objErrStage1("comptime implicit cast f64 to f32",
\\export fn entry() void {
\\ const x: f64 = 16777217;
\\ const y: f32 = x;
+ \\ _ = y;
\\}
, &[_][]const u8{
"tmp.zig:3:20: error: cast of value 16777217.000000 to type 'f32' loses information",
});
- cases.add("implicit cast from f64 to f32",
+ ctx.objErrStage1("implicit cast from f64 to f32",
\\var x: f64 = 1.0;
\\var y: f32 = x;
\\
@@ -3221,41 +3353,46 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:14: error: expected type 'f32', found 'f64'",
});
- cases.add("exceeded maximum bit width of integer",
+ ctx.objErrStage1("exceeded maximum bit width of integer",
\\export fn entry1() void {
\\ const T = u65536;
+ \\ _ = T;
\\}
\\export fn entry2() void {
\\ var x: i65536 = 1;
+ \\ _ = x;
\\}
, &[_][]const u8{
- "tmp.zig:5:12: error: primitive integer type 'i65536' exceeds maximum bit width of 65535",
+ "tmp.zig:2:15: error: primitive integer type 'u65536' exceeds maximum bit width of 65535",
+ "tmp.zig:6:12: error: primitive integer type 'i65536' exceeds maximum bit width of 65535",
});
- cases.add("compile error when evaluating return type of inferred error set",
+ ctx.objErrStage1("compile error when evaluating return type of inferred error set",
\\const Car = struct {
\\ foo: *SymbolThatDoesNotExist,
\\ pub fn init() !Car {}
\\};
\\export fn entry() void {
\\ const car = Car.init();
+ \\ _ = car;
\\}
, &[_][]const u8{
"tmp.zig:2:11: error: use of undeclared identifier 'SymbolThatDoesNotExist'",
});
- cases.add("don't implicit cast double pointer to *c_void",
+ ctx.objErrStage1("don't implicit cast double pointer to *c_void",
\\export fn entry() void {
\\ var a: u32 = 1;
\\ var ptr: *align(@alignOf(u32)) c_void = &a;
\\ var b: *u32 = @ptrCast(*u32, ptr);
\\ var ptr2: *c_void = &b;
+ \\ _ = ptr2;
\\}
, &[_][]const u8{
"tmp.zig:5:26: error: expected type '*c_void', found '**u32'",
});
- cases.add("runtime index into comptime type slice",
+ ctx.objErrStage1("runtime index into comptime type slice",
\\const Struct = struct {
\\ a: u32,
\\};
@@ -3265,12 +3402,13 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\export fn entry() void {
\\ const index = getIndex();
\\ const field = @typeInfo(Struct).Struct.fields[index];
+ \\ _ = field;
\\}
, &[_][]const u8{
"tmp.zig:9:51: error: values of type 'std.builtin.StructField' must be comptime known, but index value is runtime known",
});
- cases.add("compile log statement inside function which must be comptime evaluated",
+ ctx.objErrStage1("compile log statement inside function which must be comptime evaluated",
\\fn Foo(comptime T: type) type {
\\ @compileLog(@typeName(T));
\\ return T;
@@ -3283,25 +3421,27 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:5: error: found compile log statement",
});
- cases.add("comptime slice of an undefined slice",
+ ctx.objErrStage1("comptime slice of an undefined slice",
\\comptime {
\\ var a: []u8 = undefined;
\\ var b = a[0..10];
+ \\ _ = b;
\\}
, &[_][]const u8{
"tmp.zig:3:14: error: slice of undefined",
});
- cases.add("implicit cast const array to mutable slice",
+ ctx.objErrStage1("implicit cast const array to mutable slice",
\\export fn entry() void {
\\ const buffer: [1]u8 = [_]u8{8};
\\ const sliceA: []u8 = &buffer;
+ \\ _ = sliceA;
\\}
, &[_][]const u8{
"tmp.zig:3:27: error: expected type '[]u8', found '*const [1]u8'",
});
- cases.add("deref slice and get len field",
+ ctx.objErrStage1("deref slice and get len field",
\\export fn entry() void {
\\ var a: []u8 = undefined;
\\ _ = a.*.len;
@@ -3310,7 +3450,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:10: error: attempt to dereference non-pointer type '[]u8'",
});
- cases.add("@ptrCast a 0 bit type to a non- 0 bit type",
+ ctx.objErrStage1("@ptrCast a 0 bit type to a non- 0 bit type",
\\export fn entry() bool {
\\ var x: u0 = 0;
\\ const p = @ptrCast(?*u0, &x);
@@ -3322,7 +3462,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:24: note: '?*u0' has in-memory bits",
});
- cases.add("comparing a non-optional pointer against null",
+ ctx.objErrStage1("comparing a non-optional pointer against null",
\\export fn entry() void {
\\ var x: i32 = 1;
\\ _ = &x == null;
@@ -3331,21 +3471,23 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:12: error: comparison of '*i32' with null",
});
- cases.add("non error sets used in merge error sets operator",
+ ctx.objErrStage1("non error sets used in merge error sets operator",
\\export fn foo() void {
\\ const Errors = u8 || u16;
+ \\ _ = Errors;
\\}
\\export fn bar() void {
\\ const Errors = error{} || u16;
+ \\ _ = Errors;
\\}
, &[_][]const u8{
"tmp.zig:2:20: error: expected error set type, found type 'u8'",
"tmp.zig:2:23: note: `||` merges error sets; `or` performs boolean OR",
- "tmp.zig:5:31: error: expected error set type, found type 'u16'",
- "tmp.zig:5:28: note: `||` merges error sets; `or` performs boolean OR",
+ "tmp.zig:6:31: error: expected error set type, found type 'u16'",
+ "tmp.zig:6:28: note: `||` merges error sets; `or` performs boolean OR",
});
- cases.add("variable initialization compile error then referenced",
+ ctx.objErrStage1("variable initialization compile error then referenced",
\\fn Undeclared() type {
\\ return T;
\\}
@@ -3357,12 +3499,13 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
\\export fn entry() void {
\\ const S = Gen();
+ \\ _ = S;
\\}
, &[_][]const u8{
"tmp.zig:2:12: error: use of undeclared identifier 'T'",
});
- cases.add("refer to the type of a generic function",
+ ctx.objErrStage1("refer to the type of a generic function",
\\export fn entry() void {
\\ const Func = fn (type) void;
\\ const f: Func = undefined;
@@ -3372,7 +3515,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:4:5: error: use of undefined value here causes undefined behavior",
});
- cases.add("accessing runtime parameter from outer function",
+ ctx.objErrStage1("accessing runtime parameter from outer function",
\\fn outer(y: u32) fn (u32) u32 {
\\ const st = struct {
\\ fn get(z: u32) u32 {
@@ -3384,6 +3527,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\export fn entry() void {
\\ var func = outer(10);
\\ var x = func(3);
+ \\ _ = x;
\\}
, &[_][]const u8{
"tmp.zig:4:24: error: 'y' not accessible from inner function",
@@ -3391,69 +3535,74 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:1:10: note: declared here",
});
- cases.add("non int passed to @intToFloat",
+ ctx.objErrStage1("non int passed to @intToFloat",
\\export fn entry() void {
\\ const x = @intToFloat(f32, 1.1);
+ \\ _ = x;
\\}
, &[_][]const u8{
"tmp.zig:2:32: error: expected int type, found 'comptime_float'",
});
- cases.add("non float passed to @floatToInt",
+ ctx.objErrStage1("non float passed to @floatToInt",
\\export fn entry() void {
\\ const x = @floatToInt(i32, @as(i32, 54));
+ \\ _ = x;
\\}
, &[_][]const u8{
"tmp.zig:2:32: error: expected float type, found 'i32'",
});
- cases.add("out of range comptime_int passed to @floatToInt",
+ ctx.objErrStage1("out of range comptime_int passed to @floatToInt",
\\export fn entry() void {
\\ const x = @floatToInt(i8, 200);
+ \\ _ = x;
\\}
, &[_][]const u8{
"tmp.zig:2:31: error: integer value 200 cannot be coerced to type 'i8'",
});
- cases.add("load too many bytes from comptime reinterpreted pointer",
+ ctx.objErrStage1("load too many bytes from comptime reinterpreted pointer",
\\export fn entry() void {
\\ const float: f32 = 5.99999999999994648725e-01;
\\ const float_ptr = &float;
\\ const int_ptr = @ptrCast(*const i64, float_ptr);
\\ const int_val = int_ptr.*;
+ \\ _ = int_val;
\\}
, &[_][]const u8{
"tmp.zig:5:28: error: attempt to read 8 bytes from pointer to f32 which is 4 bytes",
});
- cases.add("invalid type used in array type",
+ ctx.objErrStage1("invalid type used in array type",
\\const Item = struct {
\\ field: SomeNonexistentType,
\\};
\\var items: [100]Item = undefined;
\\export fn entry() void {
\\ const a = items[0];
+ \\ _ = a;
\\}
, &[_][]const u8{
"tmp.zig:2:12: error: use of undeclared identifier 'SomeNonexistentType'",
});
- cases.add("comptime continue inside runtime catch",
- \\export fn entry(c: bool) void {
+ ctx.objErrStage1("comptime continue inside runtime catch",
+ \\export fn entry() void {
\\ const ints = [_]u8{ 1, 2 };
\\ inline for (ints) |_| {
- \\ bad() catch |_| continue;
+ \\ bad() catch continue;
\\ }
\\}
\\fn bad() !void {
\\ return error.Bad;
\\}
, &[_][]const u8{
- "tmp.zig:4:25: error: comptime control flow inside runtime block",
+ "tmp.zig:4:21: error: comptime control flow inside runtime block",
"tmp.zig:4:15: note: runtime block created here",
});
- cases.add("comptime continue inside runtime switch",
+ ctx.objErrStage1("comptime continue inside runtime switch",
\\export fn entry() void {
\\ var p: i32 = undefined;
\\ comptime var q = true;
@@ -3470,7 +3619,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:5:9: note: runtime block created here",
});
- cases.add("comptime continue inside runtime while error",
+ ctx.objErrStage1("comptime continue inside runtime while error",
\\export fn entry() void {
\\ var p: anyerror!usize = undefined;
\\ comptime var q = true;
@@ -3486,7 +3635,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:5:9: note: runtime block created here",
});
- cases.add("comptime continue inside runtime while optional",
+ ctx.objErrStage1("comptime continue inside runtime while optional",
\\export fn entry() void {
\\ var p: ?usize = undefined;
\\ comptime var q = true;
@@ -3500,7 +3649,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:5:9: note: runtime block created here",
});
- cases.add("comptime continue inside runtime while bool",
+ ctx.objErrStage1("comptime continue inside runtime while bool",
\\export fn entry() void {
\\ var p: usize = undefined;
\\ comptime var q = true;
@@ -3514,7 +3663,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:5:9: note: runtime block created here",
});
- cases.add("comptime continue inside runtime if error",
+ ctx.objErrStage1("comptime continue inside runtime if error",
\\export fn entry() void {
\\ var p: anyerror!i32 = undefined;
\\ comptime var q = true;
@@ -3528,7 +3677,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:5:9: note: runtime block created here",
});
- cases.add("comptime continue inside runtime if optional",
+ ctx.objErrStage1("comptime continue inside runtime if optional",
\\export fn entry() void {
\\ var p: ?i32 = undefined;
\\ comptime var q = true;
@@ -3542,7 +3691,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:5:9: note: runtime block created here",
});
- cases.add("comptime continue inside runtime if bool",
+ ctx.objErrStage1("comptime continue inside runtime if bool",
\\export fn entry() void {
\\ var p: usize = undefined;
\\ comptime var q = true;
@@ -3556,22 +3705,23 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:5:9: note: runtime block created here",
});
- cases.add("switch with invalid expression parameter",
+ ctx.objErrStage1("switch with invalid expression parameter",
\\export fn entry() void {
\\ Test(i32);
\\}
\\fn Test(comptime T: type) void {
\\ const x = switch (T) {
- \\ []u8 => |x| 123,
- \\ i32 => |x| 456,
+ \\ []u8 => |x| x,
+ \\ i32 => |x| x,
\\ else => unreachable,
\\ };
+ \\ _ = x;
\\}
, &[_][]const u8{
"tmp.zig:7:17: error: switch on type 'type' provides no expression parameter",
});
- cases.add("function prototype with no body",
+ ctx.objErrStage1("function prototype with no body",
\\fn foo() void;
\\export fn entry() void {
\\ foo();
@@ -3580,7 +3730,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:1:1: error: non-extern function has no body",
});
- cases.add("@frame() called outside of function definition",
+ ctx.objErrStage1("@frame() called outside of function definition",
\\var handle_undef: anyframe = undefined;
\\var handle_dummy: anyframe = @frame();
\\export fn entry() bool {
@@ -3590,16 +3740,17 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:30: error: @frame() called outside of function definition",
});
- cases.add("`_` is not a declarable symbol",
+ ctx.objErrStage1("`_` is not a declarable symbol",
\\export fn f1() usize {
\\ var _: usize = 2;
\\ return _;
\\}
, &[_][]const u8{
- "tmp.zig:2:5: error: `_` is not a declarable symbol",
+ "tmp.zig:2:5: error: '_' used as an identifier without @\"_\" syntax",
+ "tmp.zig:3:12: error: '_' used as an identifier without @\"_\" syntax",
});
- cases.add("`_` should not be usable inside for",
+ ctx.objErrStage1("`_` should not be usable inside for",
\\export fn returns() void {
\\ for ([_]void{}) |_, i| {
\\ for ([_]void{}) |_, j| {
@@ -3608,10 +3759,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ }
\\}
, &[_][]const u8{
- "tmp.zig:4:20: error: `_` may only be used to assign things to",
+ "tmp.zig:4:20: error: '_' used as an identifier without @\"_\" syntax",
});
- cases.add("`_` should not be usable inside while",
+ ctx.objErrStage1("`_` should not be usable inside while",
\\export fn returns() void {
\\ while (optionalReturn()) |_| {
\\ while (optionalReturn()) |_| {
@@ -3623,10 +3774,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return 1;
\\}
, &[_][]const u8{
- "tmp.zig:4:20: error: `_` may only be used to assign things to",
+ "tmp.zig:4:20: error: '_' used as an identifier without @\"_\" syntax",
});
- cases.add("`_` should not be usable inside while else",
+ ctx.objErrStage1("`_` should not be usable inside while else",
\\export fn returns() void {
\\ while (optionalReturnError()) |_| {
\\ while (optionalReturnError()) |_| {
@@ -3640,10 +3791,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return error.optionalReturnError;
\\}
, &[_][]const u8{
- "tmp.zig:6:17: error: `_` may only be used to assign things to",
+ "tmp.zig:6:17: error: '_' used as an identifier without @\"_\" syntax",
});
- cases.add("while loop body expression ignored",
+ ctx.objErrStage1("while loop body expression ignored",
\\fn returns() usize {
\\ return 2;
\\}
@@ -3664,7 +3815,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:13:26: error: expression value is ignored",
});
- cases.add("missing parameter name of generic function",
+ ctx.objErrStage1("missing parameter name of generic function",
\\fn dump(anytype) void {}
\\export fn entry() void {
\\ var a: u8 = 9;
@@ -3674,20 +3825,20 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:1:9: error: missing parameter name",
});
- cases.add("non-inline for loop on a type that requires comptime",
+ ctx.objErrStage1("non-inline for loop on a type that requires comptime",
\\const Foo = struct {
\\ name: []const u8,
\\ T: type,
\\};
\\export fn entry() void {
\\ const xx: [2]Foo = undefined;
- \\ for (xx) |f| {}
+ \\ for (xx) |f| { _ = f;}
\\}
, &[_][]const u8{
"tmp.zig:7:5: error: values of type 'Foo' must be comptime known, but index value is runtime known",
});
- cases.add("generic fn as parameter without comptime keyword",
+ ctx.objErrStage1("generic fn as parameter without comptime keyword",
\\fn f(_: fn (anytype) void) void {}
\\fn g(_: anytype) void {}
\\export fn entry() void {
@@ -3697,7 +3848,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:1:9: error: parameter of type 'fn(anytype) anytype' must be declared comptime",
});
- cases.add("optional pointer to void in extern struct",
+ ctx.objErrStage1("optional pointer to void in extern struct",
\\const Foo = extern struct {
\\ x: ?*const void,
\\};
@@ -3705,12 +3856,12 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ foo: Foo,
\\ y: i32,
\\};
- \\export fn entry(bar: *Bar) void {}
+ \\export fn entry(bar: *Bar) void {_ = bar;}
, &[_][]const u8{
"tmp.zig:2:5: error: extern structs cannot contain fields of type '?*const void'",
});
- cases.add("use of comptime-known undefined function value",
+ ctx.objErrStage1("use of comptime-known undefined function value",
\\const Cmd = struct {
\\ exec: fn () void,
\\};
@@ -3722,7 +3873,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:6:12: error: use of undefined value here causes undefined behavior",
});
- cases.add("use of comptime-known undefined function value",
+ ctx.objErrStage1("use of comptime-known undefined function value",
\\const Cmd = struct {
\\ exec: fn () void,
\\};
@@ -3734,16 +3885,17 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:6:12: error: use of undefined value here causes undefined behavior",
});
- cases.add("bad @alignCast at comptime",
+ ctx.objErrStage1("bad @alignCast at comptime",
\\comptime {
\\ const ptr = @intToPtr(*align(1) i32, 0x1);
\\ const aligned = @alignCast(4, ptr);
+ \\ _ = aligned;
\\}
, &[_][]const u8{
"tmp.zig:3:35: error: pointer address 0x1 is not aligned to 4 bytes",
});
- cases.add("@ptrToInt on *void",
+ ctx.objErrStage1("@ptrToInt on *void",
\\export fn entry() bool {
\\ return @ptrToInt(&{}) == @ptrToInt(&{});
\\}
@@ -3751,7 +3903,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:23: error: pointer to size 0 type has no address",
});
- cases.add("@popCount - non-integer",
+ ctx.objErrStage1("@popCount - non-integer",
\\export fn entry(x: f32) u32 {
\\ return @popCount(f32, x);
\\}
@@ -3759,8 +3911,23 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:22: error: expected integer type, found 'f32'",
});
- cases.addCase(x: {
- const tc = cases.create("wrong same named struct",
+ {
+ const case = ctx.obj("wrong same named struct", .{});
+ case.backend = .stage1;
+
+ case.addSourceFile("a.zig",
+ \\pub const Foo = struct {
+ \\ x: i32,
+ \\};
+ );
+
+ case.addSourceFile("b.zig",
+ \\pub const Foo = struct {
+ \\ z: f64,
+ \\};
+ );
+
+ case.addError(
\\const a = @import("a.zig");
\\const b = @import("b.zig");
\\
@@ -3769,30 +3936,16 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ bar(&a1);
\\}
\\
- \\fn bar(x: *b.Foo) void {}
+ \\fn bar(x: *b.Foo) void {_ = x;}
, &[_][]const u8{
"tmp.zig:6:10: error: expected type '*b.Foo', found '*a.Foo'",
"tmp.zig:6:10: note: pointer type child 'a.Foo' cannot cast into pointer type child 'b.Foo'",
"a.zig:1:17: note: a.Foo declared here",
"b.zig:1:17: note: b.Foo declared here",
});
+ }
- tc.addSourceFile("a.zig",
- \\pub const Foo = struct {
- \\ x: i32,
- \\};
- );
-
- tc.addSourceFile("b.zig",
- \\pub const Foo = struct {
- \\ z: f64,
- \\};
- );
-
- break :x tc;
- });
-
- cases.add("@floatToInt comptime safety",
+ ctx.objErrStage1("@floatToInt comptime safety",
\\comptime {
\\ _ = @floatToInt(i8, @as(f32, -129.1));
\\}
@@ -3808,35 +3961,38 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:8:9: error: integer value '256' cannot be stored in type 'u8'",
});
- cases.add("use c_void as return type of fn ptr",
+ ctx.objErrStage1("use c_void as return type of fn ptr",
\\export fn entry() void {
\\ const a: fn () c_void = undefined;
+ \\ _ = a;
\\}
, &[_][]const u8{
"tmp.zig:2:20: error: return type cannot be opaque",
});
- cases.add("use implicit casts to assign null to non-nullable pointer",
+ ctx.objErrStage1("use implicit casts to assign null to non-nullable pointer",
\\export fn entry() void {
\\ var x: i32 = 1234;
\\ var p: *i32 = &x;
\\ var pp: *?*i32 = &p;
\\ pp.* = null;
\\ var y = p.*;
+ \\ _ = y;
\\}
, &[_][]const u8{
"tmp.zig:4:23: error: expected type '*?*i32', found '**i32'",
});
- cases.add("attempted implicit cast from T to [*]const T",
+ ctx.objErrStage1("attempted implicit cast from T to [*]const T",
\\export fn entry() void {
\\ const x: [*]const bool = true;
+ \\ _ = x;
\\}
, &[_][]const u8{
"tmp.zig:2:30: error: expected type '[*]const bool', found 'bool'",
});
- cases.add("dereference unknown length pointer",
+ ctx.objErrStage1("dereference unknown length pointer",
\\export fn entry(x: [*]i32) i32 {
\\ return x.*;
\\}
@@ -3844,7 +4000,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:13: error: index syntax required for unknown-length pointer type '[*]i32'",
});
- cases.add("field access of unknown length pointer",
+ ctx.objErrStage1("field access of unknown length pointer",
\\const Foo = extern struct {
\\ a: i32,
\\};
@@ -3856,13 +4012,13 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:6:8: error: type '[*]Foo' does not support field access",
});
- cases.add("unknown length pointer to opaque",
+ ctx.objErrStage1("unknown length pointer to opaque",
\\export const T = [*]opaque {};
, &[_][]const u8{
"tmp.zig:1:21: error: unknown-length pointer to opaque",
});
- cases.add("error when evaluating return type",
+ ctx.objErrStage1("error when evaluating return type",
\\const Foo = struct {
\\ map: @as(i32, i32),
\\
@@ -3872,20 +4028,22 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\};
\\export fn entry() void {
\\ var rule_set = try Foo.init();
+ \\ _ = rule_set;
\\}
, &[_][]const u8{
"tmp.zig:2:19: error: expected type 'i32', found 'type'",
});
- cases.add("slicing single-item pointer",
+ ctx.objErrStage1("slicing single-item pointer",
\\export fn entry(ptr: *i32) void {
\\ const slice = ptr[0..2];
+ \\ _ = slice;
\\}
, &[_][]const u8{
"tmp.zig:2:22: error: slice of single-item pointer",
});
- cases.add("indexing single-item pointer",
+ ctx.objErrStage1("indexing single-item pointer",
\\export fn entry(ptr: *i32) i32 {
\\ return ptr[1];
\\}
@@ -3893,12 +4051,13 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:15: error: index of single-item pointer",
});
- cases.add("nested error set mismatch",
+ ctx.objErrStage1("nested error set mismatch",
\\const NextError = error{NextError};
\\const OtherError = error{OutOfMemory};
\\
\\export fn entry() void {
\\ const a: ?NextError!i32 = foo();
+ \\ _ = a;
\\}
\\
\\fn foo() ?OtherError!i32 {
@@ -3911,7 +4070,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:26: note: 'error.OutOfMemory' not a member of destination error set",
});
- cases.add("invalid deref on switch target",
+ ctx.objErrStage1("invalid deref on switch target",
\\comptime {
\\ var tile = Tile.Empty;
\\ switch (tile.*) {
@@ -3927,13 +4086,13 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:17: error: attempt to dereference non-pointer type 'Tile'",
});
- cases.add("invalid field access in comptime",
- \\comptime { var x = doesnt_exist.whatever; }
+ ctx.objErrStage1("invalid field access in comptime",
+ \\comptime { var x = doesnt_exist.whatever; _ = x; }
, &[_][]const u8{
"tmp.zig:1:20: error: use of undeclared identifier 'doesnt_exist'",
});
- cases.add("suspend inside suspend block",
+ ctx.objErrStage1("suspend inside suspend block",
\\export fn entry() void {
\\ _ = async foo();
\\}
@@ -3948,17 +4107,18 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:5:5: note: other suspend block here",
});
- cases.add("assign inline fn to non-comptime var",
+ ctx.objErrStage1("assign inline fn to non-comptime var",
\\export fn entry() void {
\\ var a = b;
+ \\ _ = a;
\\}
\\fn b() callconv(.Inline) void { }
, &[_][]const u8{
"tmp.zig:2:5: error: functions marked inline must be stored in const or comptime var",
- "tmp.zig:4:1: note: declared here",
+ "tmp.zig:5:1: note: declared here",
});
- cases.add("wrong type passed to @panic",
+ ctx.objErrStage1("wrong type passed to @panic",
\\export fn entry() void {
\\ var e = error.Foo;
\\ @panic(e);
@@ -3967,7 +4127,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:12: error: expected type '[]const u8', found 'error{Foo}'",
});
- cases.add("@tagName used on union with no associated enum tag",
+ ctx.objErrStage1("@tagName used on union with no associated enum tag",
\\const FloatInt = extern union {
\\ Float: f32,
\\ Int: i32,
@@ -3975,13 +4135,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\export fn entry() void {
\\ var fi = FloatInt{.Float = 123.45};
\\ var tagName = @tagName(fi);
+ \\ _ = tagName;
\\}
, &[_][]const u8{
"tmp.zig:7:19: error: union has no associated enum",
"tmp.zig:1:18: note: declared here",
});
- cases.add("returning error from void async function",
+ ctx.objErrStage1("returning error from void async function",
\\export fn entry() void {
\\ _ = async amain();
\\}
@@ -3992,37 +4153,40 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:5:17: error: expected type 'void', found 'error{ShouldBeCompileError}'",
});
- cases.add("var makes structs required to be comptime known",
+ ctx.objErrStage1("var makes structs required to be comptime known",
\\export fn entry() void {
\\ const S = struct{v: anytype};
\\ var s = S{.v=@as(i32, 10)};
+ \\ _ = s;
\\}
, &[_][]const u8{
"tmp.zig:3:4: error: variable of type 'S' must be const or comptime",
});
- cases.add("@ptrCast discards const qualifier",
+ ctx.objErrStage1("@ptrCast discards const qualifier",
\\export fn entry() void {
\\ const x: i32 = 1234;
\\ const y = @ptrCast(*i32, &x);
+ \\ _ = y;
\\}
, &[_][]const u8{
"tmp.zig:3:15: error: cast discards const qualifier",
});
- cases.add("comptime slice of undefined pointer non-zero len",
+ ctx.objErrStage1("comptime slice of undefined pointer non-zero len",
\\export fn entry() void {
\\ const slice = @as([*]i32, undefined)[0..1];
+ \\ _ = slice;
\\}
, &[_][]const u8{
"tmp.zig:2:41: error: non-zero length slice of undefined pointer",
});
- cases.add("type checking function pointers",
+ ctx.objErrStage1("type checking function pointers",
\\fn a(b: fn (*const u8) void) void {
\\ b('a');
\\}
- \\fn c(d: u8) void {}
+ \\fn c(d: u8) void {_ = d;}
\\export fn entry() void {
\\ a(c);
\\}
@@ -4030,7 +4194,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:6:7: error: expected type 'fn(*const u8) void', found 'fn(u8) void'",
});
- cases.add("no else prong on switch on global error set",
+ ctx.objErrStage1("no else prong on switch on global error set",
\\export fn entry() void {
\\ foo(error.A);
\\}
@@ -4043,7 +4207,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:5:5: error: else prong required when switching on type 'anyerror'",
});
- cases.add("error not handled in switch",
+ ctx.objErrStage1("error not handled in switch",
\\export fn entry() void {
\\ foo(452) catch |err| switch (err) {
\\ error.Foo => {},
@@ -4062,7 +4226,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:26: error: error.Bar not handled in switch",
});
- cases.add("duplicate error in switch",
+ ctx.objErrStage1("duplicate error in switch",
\\export fn entry() void {
\\ foo(452) catch |err| switch (err) {
\\ error.Foo => {},
@@ -4083,7 +4247,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:14: note: other value is here",
});
- cases.add("invalid cast from integral type to enum",
+ ctx.objErrStage1("invalid cast from integral type to enum",
\\const E = enum(usize) { One, Two };
\\
\\export fn entry() void {
@@ -4099,7 +4263,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:9:10: error: expected type 'usize', found 'E'",
});
- cases.add("range operator in switch used on error set",
+ ctx.objErrStage1("range operator in switch used on error set",
\\export fn entry() void {
\\ try foo(452) catch |err| switch (err) {
\\ error.A ... error.B => {},
@@ -4117,33 +4281,35 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:17: error: operator not allowed for errors",
});
- cases.add("inferring error set of function pointer",
+ ctx.objErrStage1("inferring error set of function pointer",
\\comptime {
\\ const z: ?fn()!void = null;
\\}
, &[_][]const u8{
- "tmp.zig:2:15: error: inferring error set of return type valid only for function definitions",
+ "tmp.zig:2:19: error: function prototype may not have inferred error set",
});
- cases.add("access non-existent member of error set",
+ ctx.objErrStage1("access non-existent member of error set",
\\const Foo = error{A};
\\comptime {
\\ const z = Foo.Bar;
+ \\ _ = z;
\\}
, &[_][]const u8{
"tmp.zig:3:18: error: no error named 'Bar' in 'Foo'",
});
- cases.add("error union operator with non error set LHS",
+ ctx.objErrStage1("error union operator with non error set LHS",
\\comptime {
\\ const z = i32!i32;
\\ var x: z = undefined;
+ \\ _ = x;
\\}
, &[_][]const u8{
"tmp.zig:2:15: error: expected error set type, found type 'i32'",
});
- cases.add("error equality but sets have no common members",
+ ctx.objErrStage1("error equality but sets have no common members",
\\const Set1 = error{A, C};
\\const Set2 = error{B, D};
\\export fn entry() void {
@@ -4158,29 +4324,32 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:7:11: error: error sets 'Set1' and 'Set2' have no common errors",
});
- cases.add("only equality binary operator allowed for error sets",
+ ctx.objErrStage1("only equality binary operator allowed for error sets",
\\comptime {
\\ const z = error.A > error.B;
+ \\ _ = z;
\\}
, &[_][]const u8{
"tmp.zig:2:23: error: operator not allowed for errors",
});
- cases.add("explicit error set cast known at comptime violates error sets",
+ ctx.objErrStage1("explicit error set cast known at comptime violates error sets",
\\const Set1 = error {A, B};
\\const Set2 = error {A, C};
\\comptime {
\\ var x = Set1.B;
\\ var y = @errSetCast(Set2, x);
+ \\ _ = y;
\\}
, &[_][]const u8{
"tmp.zig:5:13: error: error.B not a member of error set 'Set2'",
});
- cases.add("cast error union of global error set to error union of smaller error set",
+ ctx.objErrStage1("cast error union of global error set to error union of smaller error set",
\\const SmallErrorSet = error{A};
\\export fn entry() void {
\\ var x: SmallErrorSet!i32 = foo();
+ \\ _ = x;
\\}
\\fn foo() anyerror!i32 {
\\ return error.B;
@@ -4191,10 +4360,11 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:35: note: cannot cast global error set into smaller set",
});
- cases.add("cast global error set to error set",
+ ctx.objErrStage1("cast global error set to error set",
\\const SmallErrorSet = error{A};
\\export fn entry() void {
\\ var x: SmallErrorSet = foo();
+ \\ _ = x;
\\}
\\fn foo() anyerror {
\\ return error.B;
@@ -4203,7 +4373,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:31: error: expected type 'SmallErrorSet', found 'anyerror'",
"tmp.zig:3:31: note: cannot cast global error set into smaller set",
});
- cases.add("recursive inferred error set",
+ ctx.objErrStage1("recursive inferred error set",
\\export fn entry() void {
\\ foo() catch unreachable;
\\}
@@ -4214,7 +4384,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:5:5: error: cannot resolve inferred error set '@typeInfo(@typeInfo(@TypeOf(foo)).Fn.return_type.?).ErrorUnion.error_set': function 'foo' not fully analyzed yet",
});
- cases.add("implicit cast of error set not a subset",
+ ctx.objErrStage1("implicit cast of error set not a subset",
\\const Set1 = error{A, B};
\\const Set2 = error{A, C};
\\export fn entry() void {
@@ -4222,13 +4392,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
\\fn foo(set1: Set1) void {
\\ var x: Set2 = set1;
+ \\ _ = x;
\\}
, &[_][]const u8{
"tmp.zig:7:19: error: expected type 'Set2', found 'Set1'",
"tmp.zig:1:23: note: 'error.B' not a member of destination error set",
});
- cases.add("int to err global invalid number",
+ ctx.objErrStage1("int to err global invalid number",
\\const Set1 = error{
\\ A,
\\ B,
@@ -4236,12 +4407,13 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\comptime {
\\ var x: u16 = 3;
\\ var y = @intToError(x);
+ \\ _ = y;
\\}
, &[_][]const u8{
"tmp.zig:7:13: error: integer value 3 represents no error",
});
- cases.add("int to err non global invalid number",
+ ctx.objErrStage1("int to err non global invalid number",
\\const Set1 = error{
\\ A,
\\ B,
@@ -4253,68 +4425,74 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\comptime {
\\ var x = @errorToInt(Set1.B);
\\ var y = @errSetCast(Set2, @intToError(x));
+ \\ _ = y;
\\}
, &[_][]const u8{
"tmp.zig:11:13: error: error.B not a member of error set 'Set2'",
});
- cases.add("duplicate error value in error set",
+ ctx.objErrStage1("duplicate error value in error set",
\\const Foo = error {
\\ Bar,
\\ Bar,
\\};
\\export fn entry() void {
\\ const a: Foo = undefined;
+ \\ _ = a;
\\}
, &[_][]const u8{
"tmp.zig:3:5: error: duplicate error: 'Bar'",
"tmp.zig:2:5: note: other error here",
});
- cases.add("cast negative integer literal to usize",
+ ctx.objErrStage1("cast negative integer literal to usize",
\\export fn entry() void {
\\ const x = @as(usize, -10);
+ \\ _ = x;
\\}
, &[_][]const u8{
"tmp.zig:2:26: error: cannot cast negative value -10 to unsigned integer type 'usize'",
});
- cases.add("use invalid number literal as array index",
+ ctx.objErrStage1("use invalid number literal as array index",
\\var v = 25;
\\export fn entry() void {
\\ var arr: [v]u8 = undefined;
+ \\ _ = arr;
\\}
, &[_][]const u8{
"tmp.zig:1:1: error: unable to infer variable type",
});
- cases.add("duplicate struct field",
+ ctx.objErrStage1("duplicate struct field",
\\const Foo = struct {
\\ Bar: i32,
\\ Bar: usize,
\\};
\\export fn entry() void {
\\ const a: Foo = undefined;
+ \\ _ = a;
\\}
, &[_][]const u8{
"tmp.zig:3:5: error: duplicate struct field: 'Bar'",
"tmp.zig:2:5: note: other field here",
});
- cases.add("duplicate union field",
+ ctx.objErrStage1("duplicate union field",
\\const Foo = union {
\\ Bar: i32,
\\ Bar: usize,
\\};
\\export fn entry() void {
\\ const a: Foo = undefined;
+ \\ _ = a;
\\}
, &[_][]const u8{
"tmp.zig:3:5: error: duplicate union field: 'Bar'",
"tmp.zig:2:5: note: other field here",
});
- cases.add("duplicate enum field",
+ ctx.objErrStage1("duplicate enum field",
\\const Foo = enum {
\\ Bar,
\\ Bar,
@@ -4322,13 +4500,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\export fn entry() void {
\\ const a: Foo = undefined;
+ \\ _ = a;
\\}
, &[_][]const u8{
"tmp.zig:3:5: error: duplicate enum field: 'Bar'",
"tmp.zig:2:5: note: other field here",
});
- cases.add("calling function with naked calling convention",
+ ctx.objErrStage1("calling function with naked calling convention",
\\export fn entry() void {
\\ foo();
\\}
@@ -4338,42 +4517,42 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:4:1: note: declared here",
});
- cases.add("function with invalid return type",
+ ctx.objErrStage1("function with invalid return type",
\\export fn foo() boid {}
, &[_][]const u8{
"tmp.zig:1:17: error: use of undeclared identifier 'boid'",
});
- cases.add("function with non-extern non-packed enum parameter",
+ ctx.objErrStage1("function with non-extern non-packed enum parameter",
\\const Foo = enum { A, B, C };
- \\export fn entry(foo: Foo) void { }
+ \\export fn entry(foo: Foo) void { _ = foo; }
, &[_][]const u8{
"tmp.zig:2:22: error: parameter of type 'Foo' not allowed in function with calling convention 'C'",
});
- cases.add("function with non-extern non-packed struct parameter",
+ ctx.objErrStage1("function with non-extern non-packed struct parameter",
\\const Foo = struct {
\\ A: i32,
\\ B: f32,
\\ C: bool,
\\};
- \\export fn entry(foo: Foo) void { }
+ \\export fn entry(foo: Foo) void { _ = foo; }
, &[_][]const u8{
"tmp.zig:6:22: error: parameter of type 'Foo' not allowed in function with calling convention 'C'",
});
- cases.add("function with non-extern non-packed union parameter",
+ ctx.objErrStage1("function with non-extern non-packed union parameter",
\\const Foo = union {
\\ A: i32,
\\ B: f32,
\\ C: bool,
\\};
- \\export fn entry(foo: Foo) void { }
+ \\export fn entry(foo: Foo) void { _ = foo; }
, &[_][]const u8{
"tmp.zig:6:22: error: parameter of type 'Foo' not allowed in function with calling convention 'C'",
});
- cases.add("switch on enum with 1 field with no prongs",
+ ctx.objErrStage1("switch on enum with 1 field with no prongs",
\\const Foo = enum { M };
\\
\\export fn entry() void {
@@ -4384,15 +4563,16 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:5:5: error: enumeration value 'Foo.M' not handled in switch",
});
- cases.add("shift by negative comptime integer",
+ ctx.objErrStage1("shift by negative comptime integer",
\\comptime {
\\ var a = 1 >> -1;
+ \\ _ = a;
\\}
, &[_][]const u8{
"tmp.zig:2:18: error: shift by negative value -1",
});
- cases.add("@panic called at compile time",
+ ctx.objErrStage1("@panic called at compile time",
\\export fn entry() void {
\\ comptime {
\\ @panic("aoeu",);
@@ -4402,20 +4582,20 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:9: error: encountered @panic at compile-time",
});
- cases.add("wrong return type for main",
+ ctx.objErrStage1("wrong return type for main",
\\pub fn main() f32 { }
, &[_][]const u8{
"error: expected return type of main to be 'void', '!void', 'noreturn', 'u8', or '!u8'",
});
- cases.add("double ?? on main return value",
+ ctx.objErrStage1("double ?? on main return value",
\\pub fn main() ??void {
\\}
, &[_][]const u8{
"error: expected return type of main to be 'void', '!void', 'noreturn', 'u8', or '!u8'",
});
- cases.add("bad identifier in function with struct defined inside function which references local const",
+ ctx.objErrStage1("bad identifier in function with struct defined inside function which references local const",
\\export fn entry() void {
\\ const BlockKind = u32;
\\
@@ -4424,12 +4604,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ };
\\
\\ bogus;
+ \\
+ \\ _ = Block;
\\}
, &[_][]const u8{
"tmp.zig:8:5: error: use of undeclared identifier 'bogus'",
});
- cases.add("labeled break not found",
+ ctx.objErrStage1("labeled break not found",
\\export fn entry() void {
\\ blah: while (true) {
\\ while (true) {
@@ -4438,10 +4620,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ }
\\}
, &[_][]const u8{
- "tmp.zig:4:13: error: label not found: 'outer'",
+ "tmp.zig:4:20: error: label not found: 'outer'",
});
- cases.add("labeled continue not found",
+ ctx.objErrStage1("labeled continue not found",
\\export fn entry() void {
\\ var i: usize = 0;
\\ blah: while (i < 10) : (i += 1) {
@@ -4451,17 +4633,17 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ }
\\}
, &[_][]const u8{
- "tmp.zig:5:13: error: labeled loop not found: 'outer'",
+ "tmp.zig:5:23: error: label not found: 'outer'",
});
- cases.add("attempt to use 0 bit type in extern fn",
+ ctx.objErrStage1("attempt to use 0 bit type in extern fn",
\\extern fn foo(ptr: fn(*void) callconv(.C) void) void;
\\
\\export fn entry() void {
\\ foo(bar);
\\}
\\
- \\fn bar(x: *void) callconv(.C) void { }
+ \\fn bar(x: *void) callconv(.C) void { _ = x; }
\\export fn entry2() void {
\\ bar(&{});
\\}
@@ -4470,7 +4652,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:7:11: error: parameter of type '*void' has 0 bits; not allowed in function with calling convention 'C'",
});
- cases.add("implicit semicolon - block statement",
+ ctx.objErrStage1("implicit semicolon - block statement",
\\export fn entry() void {
\\ {}
\\ var good = {};
@@ -4478,10 +4660,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var bad = {};
\\}
, &[_][]const u8{
- "tmp.zig:5:5: error: expected token ';', found 'var'",
+ "tmp.zig:5:5: error: expected ';', found 'var'",
});
- cases.add("implicit semicolon - block expr",
+ ctx.objErrStage1("implicit semicolon - block expr",
\\export fn entry() void {
\\ _ = {};
\\ var good = {};
@@ -4489,10 +4671,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var bad = {};
\\}
, &[_][]const u8{
- "tmp.zig:5:5: error: expected token ';', found 'var'",
+ "tmp.zig:5:5: error: expected ';', found 'var'",
});
- cases.add("implicit semicolon - comptime statement",
+ ctx.objErrStage1("implicit semicolon - comptime statement",
\\export fn entry() void {
\\ comptime {}
\\ var good = {};
@@ -4500,10 +4682,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var bad = {};
\\}
, &[_][]const u8{
- "tmp.zig:5:5: error: expected token ';', found 'var'",
+ "tmp.zig:5:5: error: expected ';', found 'var'",
});
- cases.add("implicit semicolon - comptime expression",
+ ctx.objErrStage1("implicit semicolon - comptime expression",
\\export fn entry() void {
\\ _ = comptime {};
\\ var good = {};
@@ -4511,10 +4693,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var bad = {};
\\}
, &[_][]const u8{
- "tmp.zig:5:5: error: expected token ';', found 'var'",
+ "tmp.zig:5:5: error: expected ';', found 'var'",
});
- cases.add("implicit semicolon - defer",
+ ctx.objErrStage1("implicit semicolon - defer",
\\export fn entry() void {
\\ defer {}
\\ var good = {};
@@ -4522,10 +4704,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var bad = {};
\\}
, &[_][]const u8{
- "tmp.zig:5:5: error: expected token ';', found 'var'",
+ "tmp.zig:5:5: error: expected ';', found 'var'",
});
- cases.add("implicit semicolon - if statement",
+ ctx.objErrStage1("implicit semicolon - if statement",
\\export fn entry() void {
\\ if(true) {}
\\ var good = {};
@@ -4533,10 +4715,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var bad = {};
\\}
, &[_][]const u8{
- "tmp.zig:5:5: error: expected token ';', found 'var'",
+ "tmp.zig:5:5: error: expected ';' or 'else', found 'var'",
});
- cases.add("implicit semicolon - if expression",
+ ctx.objErrStage1("implicit semicolon - if expression",
\\export fn entry() void {
\\ _ = if(true) {};
\\ var good = {};
@@ -4544,10 +4726,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var bad = {};
\\}
, &[_][]const u8{
- "tmp.zig:5:5: error: expected token ';', found 'var'",
+ "tmp.zig:5:5: error: expected ';', found 'var'",
});
- cases.add("implicit semicolon - if-else statement",
+ ctx.objErrStage1("implicit semicolon - if-else statement",
\\export fn entry() void {
\\ if(true) {} else {}
\\ var good = {};
@@ -4555,10 +4737,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var bad = {};
\\}
, &[_][]const u8{
- "tmp.zig:5:5: error: expected token ';', found 'var'",
+ "tmp.zig:5:5: error: expected ';', found 'var'",
});
- cases.add("implicit semicolon - if-else expression",
+ ctx.objErrStage1("implicit semicolon - if-else expression",
\\export fn entry() void {
\\ _ = if(true) {} else {};
\\ var good = {};
@@ -4566,10 +4748,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var bad = {};
\\}
, &[_][]const u8{
- "tmp.zig:5:5: error: expected token ';', found 'var'",
+ "tmp.zig:5:5: error: expected ';', found 'var'",
});
- cases.add("implicit semicolon - if-else-if statement",
+ ctx.objErrStage1("implicit semicolon - if-else-if statement",
\\export fn entry() void {
\\ if(true) {} else if(true) {}
\\ var good = {};
@@ -4577,10 +4759,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var bad = {};
\\}
, &[_][]const u8{
- "tmp.zig:5:5: error: expected token ';', found 'var'",
+ "tmp.zig:5:5: error: expected ';' or 'else', found 'var'",
});
- cases.add("implicit semicolon - if-else-if expression",
+ ctx.objErrStage1("implicit semicolon - if-else-if expression",
\\export fn entry() void {
\\ _ = if(true) {} else if(true) {};
\\ var good = {};
@@ -4588,10 +4770,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var bad = {};
\\}
, &[_][]const u8{
- "tmp.zig:5:5: error: expected token ';', found 'var'",
+ "tmp.zig:5:5: error: expected ';', found 'var'",
});
- cases.add("implicit semicolon - if-else-if-else statement",
+ ctx.objErrStage1("implicit semicolon - if-else-if-else statement",
\\export fn entry() void {
\\ if(true) {} else if(true) {} else {}
\\ var good = {};
@@ -4599,10 +4781,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var bad = {};
\\}
, &[_][]const u8{
- "tmp.zig:5:5: error: expected token ';', found 'var'",
+ "tmp.zig:5:5: error: expected ';', found 'var'",
});
- cases.add("implicit semicolon - if-else-if-else expression",
+ ctx.objErrStage1("implicit semicolon - if-else-if-else expression",
\\export fn entry() void {
\\ _ = if(true) {} else if(true) {} else {};
\\ var good = {};
@@ -4610,10 +4792,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var bad = {};
\\}
, &[_][]const u8{
- "tmp.zig:5:5: error: expected token ';', found 'var'",
+ "tmp.zig:5:5: error: expected ';', found 'var'",
});
- cases.add("implicit semicolon - test statement",
+ ctx.objErrStage1("implicit semicolon - test statement",
\\export fn entry() void {
\\ if (foo()) |_| {}
\\ var good = {};
@@ -4621,10 +4803,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var bad = {};
\\}
, &[_][]const u8{
- "tmp.zig:5:5: error: expected token ';', found 'var'",
+ "tmp.zig:5:5: error: expected ';' or 'else', found 'var'",
});
- cases.add("implicit semicolon - test expression",
+ ctx.objErrStage1("implicit semicolon - test expression",
\\export fn entry() void {
\\ _ = if (foo()) |_| {};
\\ var good = {};
@@ -4632,10 +4814,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var bad = {};
\\}
, &[_][]const u8{
- "tmp.zig:5:5: error: expected token ';', found 'var'",
+ "tmp.zig:5:5: error: expected ';', found 'var'",
});
- cases.add("implicit semicolon - while statement",
+ ctx.objErrStage1("implicit semicolon - while statement",
\\export fn entry() void {
\\ while(true) {}
\\ var good = {};
@@ -4643,10 +4825,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var bad = {};
\\}
, &[_][]const u8{
- "tmp.zig:5:5: error: expected token ';', found 'var'",
+ "tmp.zig:5:5: error: expected ';' or 'else', found 'var'",
});
- cases.add("implicit semicolon - while expression",
+ ctx.objErrStage1("implicit semicolon - while expression",
\\export fn entry() void {
\\ _ = while(true) {};
\\ var good = {};
@@ -4654,10 +4836,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var bad = {};
\\}
, &[_][]const u8{
- "tmp.zig:5:5: error: expected token ';', found 'var'",
+ "tmp.zig:5:5: error: expected ';', found 'var'",
});
- cases.add("implicit semicolon - while-continue statement",
+ ctx.objErrStage1("implicit semicolon - while-continue statement",
\\export fn entry() void {
\\ while(true):({}) {}
\\ var good = {};
@@ -4665,10 +4847,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var bad = {};
\\}
, &[_][]const u8{
- "tmp.zig:5:5: error: expected token ';', found 'var'",
+ "tmp.zig:5:5: error: expected ';' or 'else', found 'var'",
});
- cases.add("implicit semicolon - while-continue expression",
+ ctx.objErrStage1("implicit semicolon - while-continue expression",
\\export fn entry() void {
\\ _ = while(true):({}) {};
\\ var good = {};
@@ -4676,10 +4858,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var bad = {};
\\}
, &[_][]const u8{
- "tmp.zig:5:5: error: expected token ';', found 'var'",
+ "tmp.zig:5:5: error: expected ';', found 'var'",
});
- cases.add("implicit semicolon - for statement",
+ ctx.objErrStage1("implicit semicolon - for statement",
\\export fn entry() void {
\\ for(foo()) |_| {}
\\ var good = {};
@@ -4687,10 +4869,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var bad = {};
\\}
, &[_][]const u8{
- "tmp.zig:5:5: error: expected token ';', found 'var'",
+ "tmp.zig:5:5: error: expected ';' or 'else', found 'var'",
});
- cases.add("implicit semicolon - for expression",
+ ctx.objErrStage1("implicit semicolon - for expression",
\\export fn entry() void {
\\ _ = for(foo()) |_| {};
\\ var good = {};
@@ -4698,32 +4880,33 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var bad = {};
\\}
, &[_][]const u8{
- "tmp.zig:5:5: error: expected token ';', found 'var'",
+ "tmp.zig:5:5: error: expected ';', found 'var'",
});
- cases.add("multiple function definitions",
+ ctx.objErrStage1("multiple function definitions",
\\fn a() void {}
\\fn a() void {}
\\export fn entry() void { a(); }
, &[_][]const u8{
- "tmp.zig:2:1: error: redefinition of 'a'",
+ "tmp.zig:2:1: error: redeclaration of 'a'",
+ "tmp.zig:1:1: error: other declaration here",
});
- cases.add("unreachable with return",
+ ctx.objErrStage1("unreachable with return",
\\fn a() noreturn {return;}
\\export fn entry() void { a(); }
, &[_][]const u8{
"tmp.zig:1:18: error: expected type 'noreturn', found 'void'",
});
- cases.add("control reaches end of non-void function",
+ ctx.objErrStage1("control reaches end of non-void function",
\\fn a() i32 {}
\\export fn entry() void { _ = a(); }
, &[_][]const u8{
"tmp.zig:1:12: error: expected type 'i32', found 'void'",
});
- cases.add("undefined function call",
+ ctx.objErrStage1("undefined function call",
\\export fn a() void {
\\ b();
\\}
@@ -4731,30 +4914,30 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:5: error: use of undeclared identifier 'b'",
});
- cases.add("wrong number of arguments",
+ ctx.objErrStage1("wrong number of arguments",
\\export fn a() void {
\\ b(1);
\\}
- \\fn b(a: i32, b: i32, c: i32) void { }
+ \\fn b(a: i32, b: i32, c: i32) void { _ = a; _ = b; _ = c; }
, &[_][]const u8{
"tmp.zig:2:6: error: expected 3 argument(s), found 1",
});
- cases.add("invalid type",
+ ctx.objErrStage1("invalid type",
\\fn a() bogus {}
\\export fn entry() void { _ = a(); }
, &[_][]const u8{
"tmp.zig:1:8: error: use of undeclared identifier 'bogus'",
});
- cases.add("pointer to noreturn",
+ ctx.objErrStage1("pointer to noreturn",
\\fn a() *noreturn {}
\\export fn entry() void { _ = a(); }
, &[_][]const u8{
"tmp.zig:1:9: error: pointer to noreturn not allowed",
});
- cases.add("unreachable code",
+ ctx.objErrStage1("unreachable code",
\\export fn a() void {
\\ return;
\\ b();
@@ -4766,14 +4949,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:5: note: control flow is diverted here",
});
- cases.add("bad import",
+ ctx.objErrStage1("bad import",
\\const bogus = @import("bogus-does-not-exist.zig",);
\\export fn entry() void { bogus.bogo(); }
, &[_][]const u8{
"tmp.zig:1:15: error: unable to find 'bogus-does-not-exist.zig'",
});
- cases.add("undeclared identifier",
+ ctx.objErrStage1("undeclared identifier",
\\export fn a() void {
\\ return
\\ b +
@@ -4783,33 +4966,36 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:5: error: use of undeclared identifier 'b'",
});
- cases.add("parameter redeclaration",
+ ctx.objErrStage1("parameter redeclaration",
\\fn f(a : i32, a : i32) void {
\\}
\\export fn entry() void { f(1, 2); }
, &[_][]const u8{
- "tmp.zig:1:15: error: redeclaration of variable 'a'",
+ "tmp.zig:1:15: error: redeclaration of parameter 'a'",
+ "tmp.zig:1:6: note: previous declaration here",
});
- cases.add("local variable redeclaration",
+ ctx.objErrStage1("local variable redeclaration",
\\export fn f() void {
\\ const a : i32 = 0;
- \\ const a = 0;
+ \\ var a = 0;
\\}
, &[_][]const u8{
- "tmp.zig:3:5: error: redeclaration of variable 'a'",
+ "tmp.zig:3:9: error: redeclaration of local const 'a'",
+ "tmp.zig:2:11: note: previous declaration here",
});
- cases.add("local variable redeclares parameter",
+ ctx.objErrStage1("local variable redeclares parameter",
\\fn f(a : i32) void {
\\ const a = 0;
\\}
\\export fn entry() void { f(1); }
, &[_][]const u8{
- "tmp.zig:2:5: error: redeclaration of variable 'a'",
+ "tmp.zig:2:11: error: redeclaration of parameter 'a'",
+ "tmp.zig:1:6: note: previous declaration here",
});
- cases.add("variable has wrong type",
+ ctx.objErrStage1("variable has wrong type",
\\export fn f() i32 {
\\ const a = "a";
\\ return a;
@@ -4818,7 +5004,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:12: error: expected type 'i32', found '*const [1:0]u8'",
});
- cases.add("if condition is bool, not int",
+ ctx.objErrStage1("if condition is bool, not int",
\\export fn f() void {
\\ if (0) {}
\\}
@@ -4826,7 +5012,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:9: error: expected type 'bool', found 'comptime_int'",
});
- cases.add("assign unreachable",
+ ctx.objErrStage1("assign unreachable",
\\export fn f() void {
\\ const a = return;
\\}
@@ -4835,22 +5021,23 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:15: note: control flow is diverted here",
});
- cases.add("unreachable variable",
+ ctx.objErrStage1("unreachable variable",
\\export fn f() void {
\\ const a: noreturn = {};
+ \\ _ = a;
\\}
, &[_][]const u8{
"tmp.zig:2:25: error: expected type 'noreturn', found 'void'",
});
- cases.add("unreachable parameter",
- \\fn f(a: noreturn) void {}
+ ctx.objErrStage1("unreachable parameter",
+ \\fn f(a: noreturn) void { _ = a; }
\\export fn entry() void { f(); }
, &[_][]const u8{
"tmp.zig:1:9: error: parameter of type 'noreturn' not allowed",
});
- cases.add("assign to constant variable",
+ ctx.objErrStage1("assign to constant variable",
\\export fn f() void {
\\ const a = 3;
\\ a = 4;
@@ -4859,7 +5046,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:9: error: cannot assign to constant",
});
- cases.add("use of undeclared identifier",
+ ctx.objErrStage1("use of undeclared identifier",
\\export fn f() void {
\\ b = 3;
\\}
@@ -4867,15 +5054,15 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:5: error: use of undeclared identifier 'b'",
});
- cases.add("const is a statement, not an expression",
+ ctx.objErrStage1("const is a statement, not an expression",
\\export fn f() void {
\\ (const a = 0);
\\}
, &[_][]const u8{
- "tmp.zig:2:6: error: invalid token: 'const'",
+ "tmp.zig:2:6: error: expected expression, found 'const'",
});
- cases.add("array access of undeclared identifier",
+ ctx.objErrStage1("array access of undeclared identifier",
\\export fn f() void {
\\ i[i] = i[i];
\\}
@@ -4883,7 +5070,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:5: error: use of undeclared identifier 'i'",
});
- cases.add("array access of non array",
+ ctx.objErrStage1("array access of non array",
\\export fn f() void {
\\ var bad : bool = undefined;
\\ bad[0] = bad[0];
@@ -4897,7 +5084,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:7:12: error: array access of non-array type 'bool'",
});
- cases.add("array access with non integer index",
+ ctx.objErrStage1("array access with non integer index",
\\export fn f() void {
\\ var array = "aoeu";
\\ var bad = false;
@@ -4913,7 +5100,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:9:15: error: expected type 'usize', found 'bool'",
});
- cases.add("write to const global variable",
+ ctx.objErrStage1("write to const global variable",
\\const x : i32 = 99;
\\fn f() void {
\\ x = 1;
@@ -4923,58 +5110,64 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:9: error: cannot assign to constant",
});
- cases.add("missing else clause",
+ ctx.objErrStage1("missing else clause",
\\fn f(b: bool) void {
\\ const x : i32 = if (b) h: { break :h 1; };
+ \\ _ = x;
\\}
\\fn g(b: bool) void {
\\ const y = if (b) h: { break :h @as(i32, 1); };
+ \\ _ = y;
\\}
\\export fn entry() void { f(true); g(true); }
, &[_][]const u8{
"tmp.zig:2:21: error: expected type 'i32', found 'void'",
- "tmp.zig:5:15: error: incompatible types: 'i32' and 'void'",
+ "tmp.zig:6:15: error: incompatible types: 'i32' and 'void'",
});
- cases.add("invalid struct field",
+ ctx.objErrStage1("invalid struct field",
\\const A = struct { x : i32, };
\\export fn f() void {
\\ var a : A = undefined;
\\ a.foo = 1;
\\ const y = a.bar;
+ \\ _ = y;
\\}
\\export fn g() void {
\\ var a : A = undefined;
\\ const y = a.bar;
+ \\ _ = y;
\\}
, &[_][]const u8{
"tmp.zig:4:6: error: no member named 'foo' in struct 'A'",
- "tmp.zig:9:16: error: no member named 'bar' in struct 'A'",
+ "tmp.zig:10:16: error: no member named 'bar' in struct 'A'",
});
- cases.add("redefinition of struct",
+ ctx.objErrStage1("redefinition of struct",
\\const A = struct { x : i32, };
\\const A = struct { y : i32, };
, &[_][]const u8{
- "tmp.zig:2:1: error: redefinition of 'A'",
+ "tmp.zig:2:1: error: redeclaration of 'A'",
+ "tmp.zig:1:1: note: other declaration here",
});
- cases.add("redefinition of enums",
- \\const A = enum {};
- \\const A = enum {};
+ ctx.objErrStage1("redefinition of enums",
+ \\const A = enum {x};
+ \\const A = enum {x};
, &[_][]const u8{
- "tmp.zig:2:1: error: redefinition of 'A'",
+ "tmp.zig:2:1: error: redeclaration of 'A'",
+ "tmp.zig:1:1: note: other declaration here",
});
- cases.add("redefinition of global variables",
+ ctx.objErrStage1("redefinition of global variables",
\\var a : i32 = 1;
\\var a : i32 = 2;
, &[_][]const u8{
- "tmp.zig:2:1: error: redefinition of 'a'",
- "tmp.zig:1:1: note: previous definition is here",
+ "tmp.zig:2:1: error: redeclaration of 'a'",
+ "tmp.zig:1:1: note: other declaration here",
});
- cases.add("duplicate field in struct value expression",
+ ctx.objErrStage1("duplicate field in struct value expression",
\\const A = struct {
\\ x : i32,
\\ y : i32,
@@ -4987,12 +5180,13 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ .x = 3,
\\ .z = 4,
\\ };
+ \\ _ = a;
\\}
, &[_][]const u8{
"tmp.zig:11:9: error: duplicate field",
});
- cases.add("missing field in struct value expression",
+ ctx.objErrStage1("missing field in struct value expression",
\\const A = struct {
\\ x : i32,
\\ y : i32,
@@ -5010,7 +5204,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:9:17: error: missing field: 'x'",
});
- cases.add("invalid field in struct value expression",
+ ctx.objErrStage1("invalid field in struct value expression",
\\const A = struct {
\\ x : i32,
\\ y : i32,
@@ -5022,12 +5216,13 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ .y = 2,
\\ .foo = 42,
\\ };
+ \\ _ = a;
\\}
, &[_][]const u8{
"tmp.zig:10:9: error: no member named 'foo' in struct 'A'",
});
- cases.add("invalid break expression",
+ ctx.objErrStage1("invalid break expression",
\\export fn f() void {
\\ break;
\\}
@@ -5035,7 +5230,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:5: error: break expression outside loop",
});
- cases.add("invalid continue expression",
+ ctx.objErrStage1("invalid continue expression",
\\export fn f() void {
\\ continue;
\\}
@@ -5043,15 +5238,15 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:5: error: continue expression outside loop",
});
- cases.add("invalid maybe type",
+ ctx.objErrStage1("invalid maybe type",
\\export fn f() void {
- \\ if (true) |x| { }
+ \\ if (true) |x| { _ = x; }
\\}
, &[_][]const u8{
"tmp.zig:2:9: error: expected optional type, found 'bool'",
});
- cases.add("cast unreachable",
+ ctx.objErrStage1("cast unreachable",
\\fn f() i32 {
\\ return @as(i32, return 1);
\\}
@@ -5061,22 +5256,22 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:21: note: control flow is diverted here",
});
- cases.add("invalid builtin fn",
+ ctx.objErrStage1("invalid builtin fn",
\\fn f() @bogus(foo) {
\\}
\\export fn entry() void { _ = f(); }
, &[_][]const u8{
- "tmp.zig:1:8: error: invalid builtin function: 'bogus'",
+ "tmp.zig:1:8: error: invalid builtin function: '@bogus'",
});
- cases.add("noalias on non pointer param",
- \\fn f(noalias x: i32) void {}
+ ctx.objErrStage1("noalias on non pointer param",
+ \\fn f(noalias x: i32) void { _ = x; }
\\export fn entry() void { f(1234); }
, &[_][]const u8{
"tmp.zig:1:6: error: noalias on non-pointer parameter",
});
- cases.add("struct init syntax for array",
+ ctx.objErrStage1("struct init syntax for array",
\\const foo = [3]u16{ .x = 1024 };
\\comptime {
\\ _ = foo;
@@ -5085,7 +5280,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:1:21: error: type '[3]u16' does not support struct initialization syntax",
});
- cases.add("type variables must be constant",
+ ctx.objErrStage1("type variables must be constant",
\\var foo = u8;
\\export fn entry() foo {
\\ return 1;
@@ -5094,12 +5289,13 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:1:1: error: variable of type 'type' must be constant",
});
- cases.add("variables shadowing types",
+ ctx.objErrStage1("variables shadowing types",
\\const Foo = struct {};
\\const Bar = struct {};
\\
\\fn f(Foo: i32) void {
\\ var Bar : i32 = undefined;
+ \\ _ = Bar;
\\}
\\
\\export fn entry() void {
@@ -5112,7 +5308,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:1: note: previous definition is here",
});
- cases.add("switch expression - missing enumeration prong",
+ ctx.objErrStage1("switch expression - missing enumeration prong",
\\const Number = enum {
\\ One,
\\ Two,
@@ -5132,7 +5328,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:8:5: error: enumeration value 'Number.Four' not handled in switch",
});
- cases.add("switch expression - duplicate enumeration prong",
+ ctx.objErrStage1("switch expression - duplicate enumeration prong",
\\const Number = enum {
\\ One,
\\ Two,
@@ -5155,7 +5351,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:10:15: note: other value is here",
});
- cases.add("switch expression - duplicate enumeration prong when else present",
+ ctx.objErrStage1("switch expression - duplicate enumeration prong when else present",
\\const Number = enum {
\\ One,
\\ Two,
@@ -5179,7 +5375,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:10:15: note: other value is here",
});
- cases.add("switch expression - multiple else prongs",
+ ctx.objErrStage1("switch expression - multiple else prongs",
\\fn f(x: u32) void {
\\ const value: bool = switch (x) {
\\ 1234 => false,
@@ -5194,7 +5390,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:5:9: error: multiple else prongs in switch expression",
});
- cases.add("switch expression - non exhaustive integer prongs",
+ ctx.objErrStage1("switch expression - non exhaustive integer prongs",
\\fn foo(x: u8) void {
\\ switch (x) {
\\ 0 => {},
@@ -5205,7 +5401,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:5: error: switch must handle all possibilities",
});
- cases.add("switch expression - duplicate or overlapping integer value",
+ ctx.objErrStage1("switch expression - duplicate or overlapping integer value",
\\fn foo(x: u8) u8 {
\\ return switch (x) {
\\ 0 ... 100 => @as(u8, 0),
@@ -5220,8 +5416,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:5:14: note: previous value is here",
});
- cases.add("switch expression - duplicate type",
+ ctx.objErrStage1("switch expression - duplicate type",
\\fn foo(comptime T: type, x: T) u8 {
+ \\ _ = x;
\\ return switch (T) {
\\ u32 => 0,
\\ u64 => 1,
@@ -5231,16 +5428,17 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
\\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",
+ "tmp.zig:6:9: error: duplicate switch value",
+ "tmp.zig:4:9: note: previous value is here",
});
- cases.add("switch expression - duplicate type (struct alias)",
+ ctx.objErrStage1("switch expression - duplicate type (struct alias)",
\\const Test = struct {
\\ bar: i32,
\\};
\\const Test2 = Test;
\\fn foo(comptime T: type, x: T) u8 {
+ \\ _ = x;
\\ return switch (T) {
\\ Test => 0,
\\ u64 => 1,
@@ -5250,11 +5448,11 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
\\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",
+ "tmp.zig:10:9: error: duplicate switch value",
+ "tmp.zig:8:9: note: previous value is here",
});
- cases.add("switch expression - switch on pointer type with no else",
+ ctx.objErrStage1("switch expression - switch on pointer type with no else",
\\fn foo(x: *u8) void {
\\ switch (x) {
\\ &y => {},
@@ -5266,7 +5464,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:5: error: else prong required when switching on type '*u8'",
});
- cases.add("global variable initializer must be constant expression",
+ ctx.objErrStage1("global variable initializer must be constant expression",
\\extern fn foo() i32;
\\const x = foo();
\\export fn entry() i32 { return x; }
@@ -5274,7 +5472,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:11: error: unable to evaluate constant expression",
});
- cases.add("array concatenation with wrong type",
+ ctx.objErrStage1("array concatenation with wrong type",
\\const src = "aoeu";
\\const derp: usize = 1234;
\\const a = derp ++ "foo";
@@ -5284,7 +5482,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:11: error: expected array, found 'usize'",
});
- cases.add("non compile time array concatenation",
+ ctx.objErrStage1("non compile time array concatenation",
\\fn f() []u8 {
\\ return s ++ "foo";
\\}
@@ -5294,7 +5492,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:12: error: unable to evaluate constant expression",
});
- cases.add("@cImport with bogus include",
+ ctx.objErrStage1("@cImport with bogus include",
\\const c = @cImport(@cInclude("bogus.h"));
\\export fn entry() usize { return @sizeOf(@TypeOf(c.bogo)); }
, &[_][]const u8{
@@ -5302,7 +5500,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
".h:1:10: note: 'bogus.h' file not found",
});
- cases.add("address of number literal",
+ ctx.objErrStage1("address of number literal",
\\const x = 3;
\\const y = &x;
\\fn foo() *const i32 { return y; }
@@ -5311,14 +5509,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:30: error: expected type '*const i32', found '*const comptime_int'",
});
- cases.add("integer overflow error",
+ ctx.objErrStage1("integer overflow error",
\\const x : u8 = 300;
\\export fn entry() usize { return @sizeOf(@TypeOf(x)); }
, &[_][]const u8{
"tmp.zig:1:16: error: integer value 300 cannot be coerced to type 'u8'",
});
- cases.add("invalid shift amount error",
+ ctx.objErrStage1("invalid shift amount error",
\\const x : u8 = 2;
\\fn f() u16 {
\\ return x << 8;
@@ -5328,7 +5526,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:17: error: integer value 8 cannot be coerced to type 'u3'",
});
- cases.add("missing function call param",
+ ctx.objErrStage1("missing function call param",
\\const Foo = struct {
\\ a: i32,
\\ b: i32,
@@ -5349,6 +5547,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\fn f(foo: *const Foo, index: usize) void {
\\ const result = members[index]();
+ \\ _ = foo;
+ \\ _ = result;
\\}
\\
\\export fn entry() usize { return @sizeOf(@TypeOf(f)); }
@@ -5356,21 +5556,21 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:20:34: error: expected 1 argument(s), found 0",
});
- cases.add("missing function name",
+ ctx.objErrStage1("missing function name",
\\fn () void {}
\\export fn entry() usize { return @sizeOf(@TypeOf(f)); }
, &[_][]const u8{
"tmp.zig:1:1: error: missing function name",
});
- cases.add("missing param name",
+ ctx.objErrStage1("missing param name",
\\fn f(i32) void {}
\\export fn entry() usize { return @sizeOf(@TypeOf(f)); }
, &[_][]const u8{
"tmp.zig:1:6: error: missing parameter name",
});
- cases.add("wrong function type",
+ ctx.objErrStage1("wrong function type",
\\const fns = [_]fn() void { a, b, c };
\\fn a() i32 {return 0;}
\\fn b() i32 {return 1;}
@@ -5380,7 +5580,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:1:28: error: expected type 'fn() void', found 'fn() i32'",
});
- cases.add("extern function pointer mismatch",
+ ctx.objErrStage1("extern function pointer mismatch",
\\const fns = [_](fn(i32)i32) { a, b, c };
\\pub fn a(x: i32) i32 {return x + 0;}
\\pub fn b(x: i32) i32 {return x + 1;}
@@ -5391,15 +5591,16 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:1:37: error: expected type 'fn(i32) i32', found 'fn(i32) callconv(.C) i32'",
});
- cases.add("colliding invalid top level functions",
+ ctx.objErrStage1("colliding invalid top level functions",
\\fn func() bogus {}
\\fn func() bogus {}
\\export fn entry() usize { return @sizeOf(@TypeOf(func)); }
, &[_][]const u8{
- "tmp.zig:2:1: error: redefinition of 'func'",
+ "tmp.zig:2:1: error: redeclaration of 'func'",
+ "tmp.zig:1:1: note: other declaration here",
});
- cases.add("non constant expression in array size",
+ ctx.objErrStage1("non constant expression in array size",
\\const Foo = struct {
\\ y: [get()]u8,
\\};
@@ -5412,7 +5613,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:12: note: called from here",
});
- cases.add("addition with non numbers",
+ ctx.objErrStage1("addition with non numbers",
\\const Foo = struct {
\\ field: i32,
\\};
@@ -5423,7 +5624,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:4:28: error: invalid operands to binary expression: 'Foo' and 'Foo'",
});
- cases.add("division by zero",
+ ctx.objErrStage1("division by zero",
\\const lit_int_x = 1 / 0;
\\const lit_float_x = 1.0 / 0.0;
\\const int_x = @as(u32, 1) / @as(u32, 0);
@@ -5440,7 +5641,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:4:31: error: division by zero",
});
- cases.add("normal string with newline",
+ ctx.objErrStage1("normal string with newline",
\\const foo = "a
\\b";
\\
@@ -5449,7 +5650,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:1:15: error: newline not allowed in string literal",
});
- cases.add("invalid comparison for function pointers",
+ ctx.objErrStage1("invalid comparison for function pointers",
\\fn foo() void {}
\\const invalid = foo > foo;
\\
@@ -5458,7 +5659,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:21: error: operator not allowed for type 'fn() void'",
});
- cases.add("generic function instance with non-constant expression",
+ ctx.objErrStage1("generic function instance with non-constant expression",
\\fn foo(comptime x: i32, y: i32) i32 { return x + y; }
\\fn test1(a: i32, b: i32) i32 {
\\ return foo(a, b);
@@ -5469,7 +5670,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:16: error: runtime value cannot be passed to comptime arg",
});
- cases.add("assign null to non-optional pointer",
+ ctx.objErrStage1("assign null to non-optional pointer",
\\const a: *u8 = null;
\\
\\export fn entry() usize { return @sizeOf(@TypeOf(a)); }
@@ -5477,26 +5678,28 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:1:16: error: expected type '*u8', found '(null)'",
});
- cases.add("indexing an array of size zero",
+ ctx.objErrStage1("indexing an array of size zero",
\\const array = [_]u8{};
\\export fn foo() void {
\\ const pointer = &array[0];
+ \\ _ = pointer;
\\}
, &[_][]const u8{
"tmp.zig:3:27: error: accessing a zero length array is not allowed",
});
- cases.add("indexing an array of size zero with runtime index",
+ ctx.objErrStage1("indexing an array of size zero with runtime index",
\\const array = [_]u8{};
\\export fn foo() void {
\\ var index: usize = 0;
\\ const pointer = &array[index];
+ \\ _ = pointer;
\\}
, &[_][]const u8{
"tmp.zig:4:27: error: accessing a zero length array is not allowed",
});
- cases.add("compile time division by zero",
+ ctx.objErrStage1("compile time division by zero",
\\const y = foo(0);
\\fn foo(x: u32) u32 {
\\ return 1 / x;
@@ -5508,7 +5711,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:1:14: note: referenced here",
});
- cases.add("branch on undefined value",
+ ctx.objErrStage1("branch on undefined value",
\\const x = if (undefined) true else false;
\\
\\export fn entry() usize { return @sizeOf(@TypeOf(x)); }
@@ -5516,7 +5719,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:1:15: error: use of undefined value here causes undefined behavior",
});
- cases.add("div on undefined value",
+ ctx.objErrStage1("div on undefined value",
\\comptime {
\\ var a: i64 = undefined;
\\ _ = a / a;
@@ -5525,7 +5728,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
});
- cases.add("div assign on undefined value",
+ ctx.objErrStage1("div assign on undefined value",
\\comptime {
\\ var a: i64 = undefined;
\\ a /= a;
@@ -5534,7 +5737,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:5: error: use of undefined value here causes undefined behavior",
});
- cases.add("mod on undefined value",
+ ctx.objErrStage1("mod on undefined value",
\\comptime {
\\ var a: i64 = undefined;
\\ _ = a % a;
@@ -5543,7 +5746,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
});
- cases.add("mod assign on undefined value",
+ ctx.objErrStage1("mod assign on undefined value",
\\comptime {
\\ var a: i64 = undefined;
\\ a %= a;
@@ -5552,7 +5755,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:5: error: use of undefined value here causes undefined behavior",
});
- cases.add("add on undefined value",
+ ctx.objErrStage1("add on undefined value",
\\comptime {
\\ var a: i64 = undefined;
\\ _ = a + a;
@@ -5561,7 +5764,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
});
- cases.add("add assign on undefined value",
+ ctx.objErrStage1("add assign on undefined value",
\\comptime {
\\ var a: i64 = undefined;
\\ a += a;
@@ -5570,7 +5773,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:5: error: use of undefined value here causes undefined behavior",
});
- cases.add("add wrap on undefined value",
+ ctx.objErrStage1("add wrap on undefined value",
\\comptime {
\\ var a: i64 = undefined;
\\ _ = a +% a;
@@ -5579,7 +5782,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
});
- cases.add("add wrap assign on undefined value",
+ ctx.objErrStage1("add wrap assign on undefined value",
\\comptime {
\\ var a: i64 = undefined;
\\ a +%= a;
@@ -5588,7 +5791,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:5: error: use of undefined value here causes undefined behavior",
});
- cases.add("sub on undefined value",
+ ctx.objErrStage1("sub on undefined value",
\\comptime {
\\ var a: i64 = undefined;
\\ _ = a - a;
@@ -5597,7 +5800,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
});
- cases.add("sub assign on undefined value",
+ ctx.objErrStage1("sub assign on undefined value",
\\comptime {
\\ var a: i64 = undefined;
\\ a -= a;
@@ -5606,7 +5809,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:5: error: use of undefined value here causes undefined behavior",
});
- cases.add("sub wrap on undefined value",
+ ctx.objErrStage1("sub wrap on undefined value",
\\comptime {
\\ var a: i64 = undefined;
\\ _ = a -% a;
@@ -5615,7 +5818,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
});
- cases.add("sub wrap assign on undefined value",
+ ctx.objErrStage1("sub wrap assign on undefined value",
\\comptime {
\\ var a: i64 = undefined;
\\ a -%= a;
@@ -5624,7 +5827,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:5: error: use of undefined value here causes undefined behavior",
});
- cases.add("mult on undefined value",
+ ctx.objErrStage1("mult on undefined value",
\\comptime {
\\ var a: i64 = undefined;
\\ _ = a * a;
@@ -5633,7 +5836,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
});
- cases.add("mult assign on undefined value",
+ ctx.objErrStage1("mult assign on undefined value",
\\comptime {
\\ var a: i64 = undefined;
\\ a *= a;
@@ -5642,7 +5845,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:5: error: use of undefined value here causes undefined behavior",
});
- cases.add("mult wrap on undefined value",
+ ctx.objErrStage1("mult wrap on undefined value",
\\comptime {
\\ var a: i64 = undefined;
\\ _ = a *% a;
@@ -5651,7 +5854,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
});
- cases.add("mult wrap assign on undefined value",
+ ctx.objErrStage1("mult wrap assign on undefined value",
\\comptime {
\\ var a: i64 = undefined;
\\ a *%= a;
@@ -5660,7 +5863,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:5: error: use of undefined value here causes undefined behavior",
});
- cases.add("shift left on undefined value",
+ ctx.objErrStage1("shift left on undefined value",
\\comptime {
\\ var a: i64 = undefined;
\\ _ = a << 2;
@@ -5669,7 +5872,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
});
- cases.add("shift left assign on undefined value",
+ ctx.objErrStage1("shift left assign on undefined value",
\\comptime {
\\ var a: i64 = undefined;
\\ a <<= 2;
@@ -5678,7 +5881,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:5: error: use of undefined value here causes undefined behavior",
});
- cases.add("shift right on undefined value",
+ ctx.objErrStage1("shift right on undefined value",
\\comptime {
\\ var a: i64 = undefined;
\\ _ = a >> 2;
@@ -5687,7 +5890,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
});
- cases.add("shift left assign on undefined value",
+ ctx.objErrStage1("shift left assign on undefined value",
\\comptime {
\\ var a: i64 = undefined;
\\ a >>= 2;
@@ -5696,7 +5899,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:5: error: use of undefined value here causes undefined behavior",
});
- cases.add("bin and on undefined value",
+ ctx.objErrStage1("bin and on undefined value",
\\comptime {
\\ var a: i64 = undefined;
\\ _ = a & a;
@@ -5705,7 +5908,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
});
- cases.add("bin and assign on undefined value",
+ ctx.objErrStage1("bin and assign on undefined value",
\\comptime {
\\ var a: i64 = undefined;
\\ a &= a;
@@ -5714,7 +5917,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:5: error: use of undefined value here causes undefined behavior",
});
- cases.add("bin or on undefined value",
+ ctx.objErrStage1("bin or on undefined value",
\\comptime {
\\ var a: i64 = undefined;
\\ _ = a | a;
@@ -5723,7 +5926,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
});
- cases.add("bin or assign on undefined value",
+ ctx.objErrStage1("bin or assign on undefined value",
\\comptime {
\\ var a: i64 = undefined;
\\ a |= a;
@@ -5732,7 +5935,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:5: error: use of undefined value here causes undefined behavior",
});
- cases.add("bin xor on undefined value",
+ ctx.objErrStage1("bin xor on undefined value",
\\comptime {
\\ var a: i64 = undefined;
\\ _ = a ^ a;
@@ -5741,7 +5944,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
});
- cases.add("bin xor assign on undefined value",
+ ctx.objErrStage1("bin xor assign on undefined value",
\\comptime {
\\ var a: i64 = undefined;
\\ a ^= a;
@@ -5750,7 +5953,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:5: error: use of undefined value here causes undefined behavior",
});
- cases.add("comparison operators with undefined value",
+ ctx.objErrStage1("comparison operators with undefined value",
\\// operator ==
\\comptime {
\\ var a: i64 = undefined;
@@ -5796,7 +5999,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:35:11: error: use of undefined value here causes undefined behavior",
});
- cases.add("and on undefined value",
+ ctx.objErrStage1("and on undefined value",
\\comptime {
\\ var a: bool = undefined;
\\ _ = a and a;
@@ -5805,7 +6008,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
});
- cases.add("or on undefined value",
+ ctx.objErrStage1("or on undefined value",
\\comptime {
\\ var a: bool = undefined;
\\ _ = a or a;
@@ -5814,7 +6017,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
});
- cases.add("negate on undefined value",
+ ctx.objErrStage1("negate on undefined value",
\\comptime {
\\ var a: i64 = undefined;
\\ _ = -a;
@@ -5823,7 +6026,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:10: error: use of undefined value here causes undefined behavior",
});
- cases.add("negate wrap on undefined value",
+ ctx.objErrStage1("negate wrap on undefined value",
\\comptime {
\\ var a: i64 = undefined;
\\ _ = -%a;
@@ -5832,7 +6035,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:11: error: use of undefined value here causes undefined behavior",
});
- cases.add("bin not on undefined value",
+ ctx.objErrStage1("bin not on undefined value",
\\comptime {
\\ var a: i64 = undefined;
\\ _ = ~a;
@@ -5841,7 +6044,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:10: error: use of undefined value here causes undefined behavior",
});
- cases.add("bool not on undefined value",
+ ctx.objErrStage1("bool not on undefined value",
\\comptime {
\\ var a: bool = undefined;
\\ _ = !a;
@@ -5850,7 +6053,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:10: error: use of undefined value here causes undefined behavior",
});
- cases.add("orelse on undefined value",
+ ctx.objErrStage1("orelse on undefined value",
\\comptime {
\\ var a: ?bool = undefined;
\\ _ = a orelse false;
@@ -5859,16 +6062,16 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:11: error: use of undefined value here causes undefined behavior",
});
- cases.add("catch on undefined value",
+ ctx.objErrStage1("catch on undefined value",
\\comptime {
\\ var a: anyerror!bool = undefined;
- \\ _ = a catch |err| false;
+ \\ _ = a catch false;
\\}
, &[_][]const u8{
"tmp.zig:3:11: error: use of undefined value here causes undefined behavior",
});
- cases.add("deref on undefined value",
+ ctx.objErrStage1("deref on undefined value",
\\comptime {
\\ var a: *u8 = undefined;
\\ _ = a.*;
@@ -5877,7 +6080,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:9: error: attempt to dereference undefined value",
});
- cases.add("endless loop in function evaluation",
+ ctx.objErrStage1("endless loop in function evaluation",
\\const seventh_fib_number = fibbonaci(7);
\\fn fibbonaci(x: i32) i32 {
\\ return fibbonaci(x - 1) + fibbonaci(x - 2);
@@ -5890,16 +6093,15 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:6:50: note: referenced here",
});
- cases.add("@embedFile with bogus file",
+ ctx.objErrStage1("@embedFile with bogus file",
\\const resource = @embedFile("bogus.txt",);
\\
\\export fn entry() usize { return @sizeOf(@TypeOf(resource)); }
, &[_][]const u8{
- "tmp.zig:1:29: error: unable to find '",
- "bogus.txt'",
+ "tmp.zig:1:29: error: unable to find 'bogus.txt'",
});
- cases.add("non-const expression in struct literal outside function",
+ ctx.objErrStage1("non-const expression in struct literal outside function",
\\const Foo = struct {
\\ x: i32,
\\};
@@ -5911,7 +6113,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:4:21: error: unable to evaluate constant expression",
});
- cases.add("non-const expression function call with struct return value outside function",
+ ctx.objErrStage1("non-const expression function call with struct return value outside function",
\\const Foo = struct {
\\ x: i32,
\\};
@@ -5928,7 +6130,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:4:17: note: referenced here",
});
- cases.add("undeclared identifier error should mark fn as impure",
+ ctx.objErrStage1("undeclared identifier error should mark fn as impure",
\\export fn foo() void {
\\ test_a_thing();
\\}
@@ -5939,7 +6141,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:5:5: error: use of undeclared identifier 'bad_fn_call'",
});
- cases.add("illegal comparison of types",
+ ctx.objErrStage1("illegal comparison of types",
\\fn bad_eql_1(a: []u8, b: []u8) bool {
\\ return a == b;
\\}
@@ -5958,13 +6160,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:9:16: error: operator not allowed for type 'EnumWithData'",
});
- cases.add("non-const switch number literal",
+ ctx.objErrStage1("non-const switch number literal",
\\export fn foo() void {
\\ const x = switch (bar()) {
\\ 1, 2 => 1,
\\ 3, 4 => 2,
\\ else => 3,
\\ };
+ \\ _ = x;
\\}
\\fn bar() i32 {
\\ return 2;
@@ -5973,7 +6176,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:5:17: error: cannot store runtime value in type 'comptime_int'",
});
- cases.add("atomic orderings of cmpxchg - failure stricter than success",
+ ctx.objErrStage1("atomic orderings of cmpxchg - failure stricter than success",
\\const AtomicOrder = @import("std").builtin.AtomicOrder;
\\export fn f() void {
\\ var x: i32 = 1234;
@@ -5983,7 +6186,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:4:81: error: failure atomic ordering must be no stricter than success",
});
- cases.add("atomic orderings of cmpxchg - success Monotonic or stricter",
+ ctx.objErrStage1("atomic orderings of cmpxchg - success Monotonic or stricter",
\\const AtomicOrder = @import("std").builtin.AtomicOrder;
\\export fn f() void {
\\ var x: i32 = 1234;
@@ -5993,7 +6196,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:4:58: error: success atomic ordering must be Monotonic or stricter",
});
- cases.add("negation overflow in function evaluation",
+ ctx.objErrStage1("negation overflow in function evaluation",
\\const y = neg(-128);
\\fn neg(x: i8) i8 {
\\ return -x;
@@ -6005,7 +6208,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:1:14: note: referenced here",
});
- cases.add("add overflow in function evaluation",
+ ctx.objErrStage1("add overflow in function evaluation",
\\const y = add(65530, 10);
\\fn add(a: u16, b: u16) u16 {
\\ return a + b;
@@ -6017,7 +6220,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:1:14: note: referenced here",
});
- cases.add("sub overflow in function evaluation",
+ ctx.objErrStage1("sub overflow in function evaluation",
\\const y = sub(10, 20);
\\fn sub(a: u16, b: u16) u16 {
\\ return a - b;
@@ -6029,7 +6232,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:1:14: note: referenced here",
});
- cases.add("mul overflow in function evaluation",
+ ctx.objErrStage1("mul overflow in function evaluation",
\\const y = mul(300, 6000);
\\fn mul(a: u16, b: u16) u16 {
\\ return a * b;
@@ -6041,7 +6244,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:1:14: note: referenced here",
});
- cases.add("truncate sign mismatch",
+ ctx.objErrStage1("truncate sign mismatch",
\\export fn entry1() i8 {
\\ var x: u32 = 10;
\\ return @truncate(i8, x);
@@ -6065,7 +6268,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:15:26: error: expected unsigned integer type, found 'i32'",
});
- cases.add("try in function with non error return type",
+ ctx.objErrStage1("try in function with non error return type",
\\export fn f() void {
\\ try something();
\\}
@@ -6074,7 +6277,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:5: error: expected type 'void', found 'anyerror'",
});
- cases.add("invalid pointer for var type",
+ ctx.objErrStage1("invalid pointer for var type",
\\extern fn ext() usize;
\\var bytes: [ext()]u8 = undefined;
\\export fn f() void {
@@ -6086,7 +6289,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:13: error: unable to evaluate constant expression",
});
- cases.add("export function with comptime parameter",
+ ctx.objErrStage1("export function with comptime parameter",
\\export fn foo(comptime x: i32, y: i32) i32{
\\ return x + y;
\\}
@@ -6094,7 +6297,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:1:15: error: comptime parameter not allowed in function with calling convention 'C'",
});
- cases.add("extern function with comptime parameter",
+ ctx.objErrStage1("extern function with comptime parameter",
\\extern fn foo(comptime x: i32, y: i32) i32;
\\fn f() i32 {
\\ return foo(1, 2);
@@ -6104,7 +6307,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:1:15: error: comptime parameter not allowed in function with calling convention 'C'",
});
- cases.add("non-pure function returns type",
+ ctx.objErrStage1("non-pure function returns type",
\\var a: u32 = 0;
\\pub fn List(comptime T: type) type {
\\ a += 1;
@@ -6128,7 +6331,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:16:19: note: referenced here",
});
- cases.add("bogus method call on slice",
+ ctx.objErrStage1("bogus method call on slice",
\\var self = "aoeu";
\\fn f(m: []const u8) void {
\\ m.copy(u8, self[0..], m);
@@ -6138,9 +6341,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:6: error: no member named 'copy' in '[]const u8'",
});
- cases.add("wrong number of arguments for method fn call",
+ ctx.objErrStage1("wrong number of arguments for method fn call",
\\const Foo = struct {
- \\ fn method(self: *const Foo, a: i32) void {}
+ \\ fn method(self: *const Foo, a: i32) void {_ = self; _ = a;}
\\};
\\fn f(foo: *const Foo) void {
\\
@@ -6151,7 +6354,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:6:15: error: expected 2 argument(s), found 3",
});
- cases.add("assign through constant pointer",
+ ctx.objErrStage1("assign through constant pointer",
\\export fn f() void {
\\ var cstr = "Hat";
\\ cstr[0] = 'W';
@@ -6160,7 +6363,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:13: error: cannot assign to constant",
});
- cases.add("assign through constant slice",
+ ctx.objErrStage1("assign through constant slice",
\\export fn f() void {
\\ var cstr: []const u8 = "Hat";
\\ cstr[0] = 'W';
@@ -6169,13 +6372,13 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:13: error: cannot assign to constant",
});
- cases.add("main function with bogus args type",
- \\pub fn main(args: [][]bogus) !void {}
+ ctx.objErrStage1("main function with bogus args type",
+ \\pub fn main(args: [][]bogus) !void {_ = args;}
, &[_][]const u8{
"tmp.zig:1:23: error: use of undeclared identifier 'bogus'",
});
- cases.add("misspelled type with pointer only reference",
+ ctx.objErrStage1("misspelled type with pointer only reference",
\\const JasonHM = u8;
\\const JasonList = *JsonNode;
\\
@@ -6203,6 +6406,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var jll: JasonList = undefined;
\\ jll.init(1234);
\\ var jd = JsonNode {.kind = JsonType.JSONArray , .jobject = JsonOA.JSONArray {jll} };
+ \\ _ = jd;
\\}
\\
\\export fn entry() usize { return @sizeOf(@TypeOf(foo)); }
@@ -6210,7 +6414,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:5:16: error: use of undeclared identifier 'JsonList'",
});
- cases.add("method call with first arg type primitive",
+ ctx.objErrStage1("method call with first arg type primitive",
\\const Foo = struct {
\\ x: i32,
\\
@@ -6230,7 +6434,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:14:5: error: expected type 'i32', found 'Foo'",
});
- cases.add("method call with first arg type wrong container",
+ ctx.objErrStage1("method call with first arg type wrong container",
\\pub const List = struct {
\\ len: usize,
\\ allocator: *Allocator,
@@ -6259,7 +6463,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:23:5: error: expected type '*Allocator', found '*List'",
});
- cases.add("binary not on number literal",
+ ctx.objErrStage1("binary not on number literal",
\\const TINY_QUANTUM_SHIFT = 4;
\\const TINY_QUANTUM_SIZE = 1 << TINY_QUANTUM_SHIFT;
\\var block_aligned_stuff: usize = (4 + TINY_QUANTUM_SIZE) & ~(TINY_QUANTUM_SIZE - 1);
@@ -6269,8 +6473,15 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:60: error: unable to perform binary not operation on type 'comptime_int'",
});
- cases.addCase(x: {
- const tc = cases.create("multiple files with private function error",
+ {
+ const case = ctx.obj("multiple files with private function error", .{});
+ case.backend = .stage1;
+
+ case.addSourceFile("foo.zig",
+ \\fn privateFunction() void { }
+ );
+
+ case.addError(
\\const foo = @import("foo.zig",);
\\
\\export fn callPrivFunction() void {
@@ -6280,16 +6491,19 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:4:8: error: 'privateFunction' is private",
"foo.zig:1:1: note: declared here",
});
+ }
- tc.addSourceFile("foo.zig",
- \\fn privateFunction() void { }
+ {
+ const case = ctx.obj("multiple files with private member instance function (canonical invocation) error", .{});
+ case.backend = .stage1;
+
+ case.addSourceFile("foo.zig",
+ \\pub const Foo = struct {
+ \\ fn privateFunction(self: *Foo) void { _ = self; }
+ \\};
);
- break :x tc;
- });
-
- cases.addCase(x: {
- const tc = cases.create("multiple files with private member instance function (canonical invocation) error",
+ case.addError(
\\const Foo = @import("foo.zig",).Foo;
\\
\\export fn callPrivFunction() void {
@@ -6300,18 +6514,19 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:5:8: error: 'privateFunction' is private",
"foo.zig:2:5: note: declared here",
});
+ }
- tc.addSourceFile("foo.zig",
+ {
+ const case = ctx.obj("multiple files with private member instance function error", .{});
+ case.backend = .stage1;
+
+ case.addSourceFile("foo.zig",
\\pub const Foo = struct {
- \\ fn privateFunction(self: *Foo) void { }
+ \\ fn privateFunction(self: *Foo) void { _ = self; }
\\};
);
- break :x tc;
- });
-
- cases.addCase(x: {
- const tc = cases.create("multiple files with private member instance function error",
+ case.addError(
\\const Foo = @import("foo.zig",).Foo;
\\
\\export fn callPrivFunction() void {
@@ -6322,17 +6537,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:5:8: error: 'privateFunction' is private",
"foo.zig:2:5: note: declared here",
});
+ }
- tc.addSourceFile("foo.zig",
- \\pub const Foo = struct {
- \\ fn privateFunction(self: *Foo) void { }
- \\};
- );
-
- break :x tc;
- });
-
- cases.add("container init with non-type",
+ ctx.objErrStage1("container init with non-type",
\\const zero: i32 = 0;
\\const a = zero{1};
\\
@@ -6341,7 +6548,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:11: error: expected type 'type', found 'i32'",
});
- cases.add("assign to constant field",
+ ctx.objErrStage1("assign to constant field",
\\const Foo = struct {
\\ field: i32,
\\};
@@ -6353,7 +6560,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:6:15: error: cannot assign to constant",
});
- cases.add("return from defer expression",
+ ctx.objErrStage1("return from defer expression",
\\pub fn testTrickyDefer() !void {
\\ defer canFail() catch {};
\\
@@ -6370,32 +6577,33 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\export fn entry() usize { return @sizeOf(@TypeOf(testTrickyDefer)); }
, &[_][]const u8{
- "tmp.zig:4:11: error: cannot return from defer expression",
+ "tmp.zig:4:11: error: 'try' is not allowed inside defer expression",
});
- cases.add("assign too big number to u16",
+ ctx.objErrStage1("assign too big number to u16",
\\export fn foo() void {
\\ var vga_mem: u16 = 0xB8000;
+ \\ _ = vga_mem;
\\}
, &[_][]const u8{
"tmp.zig:2:24: error: integer value 753664 cannot be coerced to type 'u16'",
});
- cases.add("global variable alignment non power of 2",
+ ctx.objErrStage1("global variable alignment non power of 2",
\\const some_data: [100]u8 align(3) = undefined;
\\export fn entry() usize { return @sizeOf(@TypeOf(some_data)); }
, &[_][]const u8{
"tmp.zig:1:32: error: alignment value 3 is not a power of 2",
});
- cases.add("function alignment non power of 2",
+ ctx.objErrStage1("function alignment non power of 2",
\\extern fn foo() align(3) void;
\\export fn entry() void { return foo(); }
, &[_][]const u8{
"tmp.zig:1:23: error: alignment value 3 is not a power of 2",
});
- cases.add("compile log",
+ ctx.objErrStage1("compile log",
\\export fn foo() void {
\\ comptime bar(12, "hi",);
\\}
@@ -6410,7 +6618,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:7:5: error: found compile log statement",
});
- cases.add("casting bit offset pointer to regular pointer",
+ ctx.objErrStage1("casting bit offset pointer to regular pointer",
\\const BitField = packed struct {
\\ a: u3,
\\ b: u3,
@@ -6430,7 +6638,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:8:26: error: expected type '*const u3', found '*align(:3:1) const u3'",
});
- cases.add("referring to a struct that is invalid",
+ ctx.objErrStage1("referring to a struct that is invalid",
\\const UsbDeviceRequest = struct {
\\ Type: u8,
\\};
@@ -6447,7 +6655,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:6:20: note: referenced here",
});
- cases.add("control flow uses comptime var at runtime",
+ ctx.objErrStage1("control flow uses comptime var at runtime",
\\export fn foo() void {
\\ comptime var i = 0;
\\ while (i < 5) : (i += 1) {
@@ -6461,7 +6669,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:24: note: compile-time variable assigned here",
});
- cases.add("ignored return value",
+ ctx.objErrStage1("ignored return value",
\\export fn foo() void {
\\ bar();
\\}
@@ -6470,7 +6678,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:8: error: expression value is ignored",
});
- cases.add("ignored assert-err-ok return value",
+ ctx.objErrStage1("ignored assert-err-ok return value",
\\export fn foo() void {
\\ bar() catch unreachable;
\\}
@@ -6479,7 +6687,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:11: error: expression value is ignored",
});
- cases.add("ignored statement value",
+ ctx.objErrStage1("ignored statement value",
\\export fn foo() void {
\\ 1;
\\}
@@ -6487,7 +6695,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:5: error: expression value is ignored",
});
- cases.add("ignored comptime statement value",
+ ctx.objErrStage1("ignored comptime statement value",
\\export fn foo() void {
\\ comptime {1;}
\\}
@@ -6495,7 +6703,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:15: error: expression value is ignored",
});
- cases.add("ignored comptime value",
+ ctx.objErrStage1("ignored comptime value",
\\export fn foo() void {
\\ comptime 1;
\\}
@@ -6503,7 +6711,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:5: error: expression value is ignored",
});
- cases.add("ignored defered statement value",
+ ctx.objErrStage1("ignored defered statement value",
\\export fn foo() void {
\\ defer {1;}
\\}
@@ -6511,7 +6719,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:12: error: expression value is ignored",
});
- cases.add("ignored defered function call",
+ ctx.objErrStage1("ignored defered function call",
\\export fn foo() void {
\\ defer bar();
\\}
@@ -6520,7 +6728,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:14: error: error is ignored. consider using `try`, `catch`, or `if`",
});
- cases.add("dereference an array",
+ ctx.objErrStage1("dereference an array",
\\var s_buffer: [10]u8 = undefined;
\\pub fn pass(in: []u8) []u8 {
\\ var out = &s_buffer;
@@ -6533,13 +6741,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:4:10: error: attempt to dereference non-pointer type '[10]u8'",
});
- cases.add("pass const ptr to mutable ptr fn",
+ ctx.objErrStage1("pass const ptr to mutable ptr fn",
\\fn foo() bool {
\\ const a = @as([]const u8, "a",);
\\ const b = &a;
\\ return ptrEql(b, b);
\\}
\\fn ptrEql(a: *[]const u8, b: *[]const u8) bool {
+ \\ _ = a; _ = b;
\\ return true;
\\}
\\
@@ -6548,8 +6757,16 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:4:19: error: expected type '*[]const u8', found '*const []const u8'",
});
- cases.addCase(x: {
- const tc = cases.create("export collision",
+ {
+ const case = ctx.obj("export collision", .{});
+ case.backend = .stage1;
+
+ case.addSourceFile("foo.zig",
+ \\export fn bar() void {}
+ \\pub const baz = 1234;
+ );
+
+ case.addError(
\\const foo = @import("foo.zig",);
\\
\\export fn bar() usize {
@@ -6559,18 +6776,11 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"foo.zig:1:1: error: exported symbol collision: 'bar'",
"tmp.zig:3:1: note: other symbol here",
});
+ }
- tc.addSourceFile("foo.zig",
- \\export fn bar() void {}
- \\pub const baz = 1234;
- );
-
- break :x tc;
- });
-
- cases.add("implicit cast from array to mutable slice",
+ ctx.objErrStage1("implicit cast from array to mutable slice",
\\var global_array: [10]i32 = undefined;
- \\fn foo(param: []i32) void {}
+ \\fn foo(param: []i32) void {_ = param;}
\\export fn entry() void {
\\ foo(global_array);
\\}
@@ -6578,7 +6788,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:4:9: error: expected type '[]i32', found '[10]i32'",
});
- cases.add("ptrcast to non-pointer",
+ ctx.objErrStage1("ptrcast to non-pointer",
\\export fn entry(a: *i32) usize {
\\ return @ptrCast(usize, a);
\\}
@@ -6586,7 +6796,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:21: error: expected pointer, found 'usize'",
});
- cases.add("asm at compile time",
+ ctx.objErrStage1("asm at compile time",
\\comptime {
\\ doSomeAsm();
\\}
@@ -6602,25 +6812,27 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:6:5: error: unable to evaluate constant expression",
});
- cases.add("invalid member of builtin enum",
+ ctx.objErrStage1("invalid member of builtin enum",
\\const builtin = @import("std").builtin;
\\export fn entry() void {
\\ const foo = builtin.Mode.x86;
+ \\ _ = foo;
\\}
, &[_][]const u8{
"tmp.zig:3:29: error: container 'std.builtin.Mode' has no member called 'x86'",
});
- cases.add("int to ptr of 0 bits",
+ ctx.objErrStage1("int to ptr of 0 bits",
\\export fn foo() void {
\\ var x: usize = 0x1000;
\\ var y: *void = @intToPtr(*void, x);
+ \\ _ = y;
\\}
, &[_][]const u8{
"tmp.zig:3:30: error: type '*void' has 0 bits and cannot store information",
});
- cases.add("@fieldParentPtr - non struct",
+ ctx.objErrStage1("@fieldParentPtr - non struct",
\\const Foo = i32;
\\export fn foo(a: *i32) *Foo {
\\ return @fieldParentPtr(Foo, "a", a);
@@ -6629,7 +6841,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:28: error: expected struct type, found 'i32'",
});
- cases.add("@fieldParentPtr - bad field name",
+ ctx.objErrStage1("@fieldParentPtr - bad field name",
\\const Foo = extern struct {
\\ derp: i32,
\\};
@@ -6640,7 +6852,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:5:33: error: struct 'Foo' has no field 'a'",
});
- cases.add("@fieldParentPtr - field pointer is not pointer",
+ ctx.objErrStage1("@fieldParentPtr - field pointer is not pointer",
\\const Foo = extern struct {
\\ a: i32,
\\};
@@ -6651,7 +6863,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:5:38: error: expected pointer, found 'i32'",
});
- cases.add("@fieldParentPtr - comptime field ptr not based on struct",
+ ctx.objErrStage1("@fieldParentPtr - comptime field ptr not based on struct",
\\const Foo = struct {
\\ a: i32,
\\ b: i32,
@@ -6661,12 +6873,13 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\comptime {
\\ const field_ptr = @intToPtr(*i32, 0x1234);
\\ const another_foo_ptr = @fieldParentPtr(Foo, "b", field_ptr);
+ \\ _ = another_foo_ptr;
\\}
, &[_][]const u8{
"tmp.zig:9:55: error: pointer value not based on parent struct",
});
- cases.add("@fieldParentPtr - comptime wrong field index",
+ ctx.objErrStage1("@fieldParentPtr - comptime wrong field index",
\\const Foo = struct {
\\ a: i32,
\\ b: i32,
@@ -6675,12 +6888,13 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\comptime {
\\ const another_foo_ptr = @fieldParentPtr(Foo, "b", &foo.a);
+ \\ _ = another_foo_ptr;
\\}
, &[_][]const u8{
"tmp.zig:8:29: error: field 'b' has index 1 but pointer value is index 0 of struct 'Foo'",
});
- cases.add("@offsetOf - non struct",
+ ctx.objErrStage1("@offsetOf - non struct",
\\const Foo = i32;
\\export fn foo() usize {
\\ return @offsetOf(Foo, "a",);
@@ -6689,7 +6903,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:22: error: expected struct type, found 'i32'",
});
- cases.add("@offsetOf - bad field name",
+ ctx.objErrStage1("@offsetOf - bad field name",
\\const Foo = struct {
\\ derp: i32,
\\};
@@ -6700,20 +6914,20 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:5:27: error: struct 'Foo' has no field 'a'",
});
- cases.addExe("missing main fn in executable",
+ ctx.exeErrStage1("missing main fn in executable",
\\
, &[_][]const u8{
"error: root source file has no member called 'main'",
});
- cases.addExe("private main fn",
+ ctx.exeErrStage1("private main fn",
\\fn main() void {}
, &[_][]const u8{
"error: 'main' is private",
"tmp.zig:1:1: note: declared here",
});
- cases.add("setting a section on a local variable",
+ ctx.objErrStage1("setting a section on a local variable",
\\export fn entry() i32 {
\\ var foo: i32 linksection(".text2") = 1234;
\\ return foo;
@@ -6722,7 +6936,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:30: error: cannot set section of local variable 'foo'",
});
- cases.add("inner struct member shadowing outer struct member",
+ ctx.objErrStage1("inner struct member shadowing outer struct member",
\\fn A() type {
\\ return struct {
\\ b: B(),
@@ -6747,7 +6961,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:5:9: note: previous definition is here",
});
- cases.add("while expected bool, got optional",
+ ctx.objErrStage1("while expected bool, got optional",
\\export fn foo() void {
\\ while (bar()) {}
\\}
@@ -6756,7 +6970,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:15: error: expected type 'bool', found '?i32'",
});
- cases.add("while expected bool, got error union",
+ ctx.objErrStage1("while expected bool, got error union",
\\export fn foo() void {
\\ while (bar()) {}
\\}
@@ -6765,36 +6979,36 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:15: error: expected type 'bool', found 'anyerror!i32'",
});
- cases.add("while expected optional, got bool",
+ ctx.objErrStage1("while expected optional, got bool",
\\export fn foo() void {
- \\ while (bar()) |x| {}
+ \\ while (bar()) |x| {_ = x;}
\\}
\\fn bar() bool { return true; }
, &[_][]const u8{
"tmp.zig:2:15: error: expected optional type, found 'bool'",
});
- cases.add("while expected optional, got error union",
+ ctx.objErrStage1("while expected optional, got error union",
\\export fn foo() void {
- \\ while (bar()) |x| {}
+ \\ while (bar()) |x| {_ = x;}
\\}
\\fn bar() anyerror!i32 { return 1; }
, &[_][]const u8{
"tmp.zig:2:15: error: expected optional type, found 'anyerror!i32'",
});
- cases.add("while expected error union, got bool",
+ ctx.objErrStage1("while expected error union, got bool",
\\export fn foo() void {
- \\ while (bar()) |x| {} else |err| {}
+ \\ while (bar()) |x| {_ = x;} else |err| {_ = err;}
\\}
\\fn bar() bool { return true; }
, &[_][]const u8{
"tmp.zig:2:15: error: expected error union type, found 'bool'",
});
- cases.add("while expected error union, got optional",
+ ctx.objErrStage1("while expected error union, got optional",
\\export fn foo() void {
- \\ while (bar()) |x| {} else |err| {}
+ \\ while (bar()) |x| {_ = x;} else |err| {_ = err;}
\\}
\\fn bar() ?i32 { return 1; }
, &[_][]const u8{
@@ -6802,7 +7016,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
});
// TODO test this in stage2, but we won't even try in stage1
- //cases.add("inline fn calls itself indirectly",
+ //ctx.objErrStage1("inline fn calls itself indirectly",
// \\export fn foo() void {
// \\ bar();
// \\}
@@ -6819,7 +7033,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
// "tmp.zig:4:1: error: unable to inline function",
//});
- //cases.add("save reference to inline function",
+ //ctx.objErrStage1("save reference to inline function",
// \\export fn foo() void {
// \\ quux(@ptrToInt(bar));
// \\}
@@ -6829,7 +7043,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
// "tmp.zig:4:1: error: unable to inline function",
//});
- cases.add("signed integer division",
+ ctx.objErrStage1("signed integer division",
\\export fn foo(a: i32, b: i32) i32 {
\\ return a / b;
\\}
@@ -6837,7 +7051,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:14: error: division with 'i32' and 'i32': signed integers must use @divTrunc, @divFloor, or @divExact",
});
- cases.add("signed integer remainder division",
+ ctx.objErrStage1("signed integer remainder division",
\\export fn foo(a: i32, b: i32) i32 {
\\ return a % b;
\\}
@@ -6845,27 +7059,29 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:14: error: remainder division with 'i32' and 'i32': signed integers and floats must use @rem or @mod",
});
- cases.add("compile-time division by zero",
+ ctx.objErrStage1("compile-time division by zero",
\\comptime {
\\ const a: i32 = 1;
\\ const b: i32 = 0;
\\ const c = a / b;
+ \\ _ = c;
\\}
, &[_][]const u8{
"tmp.zig:4:17: error: division by zero",
});
- cases.add("compile-time remainder division by zero",
+ ctx.objErrStage1("compile-time remainder division by zero",
\\comptime {
\\ const a: i32 = 1;
\\ const b: i32 = 0;
\\ const c = a % b;
+ \\ _ = c;
\\}
, &[_][]const u8{
"tmp.zig:4:17: error: division by zero",
});
- cases.add("@setRuntimeSafety twice for same scope",
+ ctx.objErrStage1("@setRuntimeSafety twice for same scope",
\\export fn foo() void {
\\ @setRuntimeSafety(false);
\\ @setRuntimeSafety(false);
@@ -6875,7 +7091,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:5: note: first set here",
});
- cases.add("@setFloatMode twice for same scope",
+ ctx.objErrStage1("@setFloatMode twice for same scope",
\\export fn foo() void {
\\ @setFloatMode(@import("std").builtin.FloatMode.Optimized);
\\ @setFloatMode(@import("std").builtin.FloatMode.Optimized);
@@ -6885,15 +7101,16 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:5: note: first set here",
});
- cases.add("array access of type",
+ ctx.objErrStage1("array access of type",
\\export fn foo() void {
\\ var b: u8[40] = undefined;
+ \\ _ = b;
\\}
, &[_][]const u8{
"tmp.zig:2:14: error: array access of non-array type 'type'",
});
- cases.add("cannot break out of defer expression",
+ ctx.objErrStage1("cannot break out of defer expression",
\\export fn foo() void {
\\ while (true) {
\\ defer {
@@ -6905,7 +7122,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:4:13: error: cannot break out of defer expression",
});
- cases.add("cannot continue out of defer expression",
+ ctx.objErrStage1("cannot continue out of defer expression",
\\export fn foo() void {
\\ while (true) {
\\ defer {
@@ -6917,11 +7134,11 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:4:13: error: cannot continue out of defer expression",
});
- cases.add("calling a generic function only known at runtime",
+ ctx.objErrStage1("calling a generic function only known at runtime",
\\var foos = [_]fn(anytype) void { foo1, foo2 };
\\
- \\fn foo1(arg: anytype) void {}
- \\fn foo2(arg: anytype) void {}
+ \\fn foo1(arg: anytype) void {_ = arg;}
+ \\fn foo2(arg: anytype) void {_ = arg;}
\\
\\pub fn main() !void {
\\ foos[0](true);
@@ -6930,7 +7147,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:7:9: error: calling a generic function requires compile-time known function value",
});
- cases.add("@compileError shows traceback of references that caused it",
+ ctx.objErrStage1("@compileError shows traceback of references that caused it",
\\const foo = @compileError("aoeu",);
\\
\\const bar = baz + foo;
@@ -6945,23 +7162,25 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:7:12: note: referenced here",
});
- cases.add("float literal too large error",
+ ctx.objErrStage1("float literal too large error",
\\comptime {
\\ const a = 0x1.0p18495;
+ \\ _ = a;
\\}
, &[_][]const u8{
"tmp.zig:2:15: error: float literal out of range of any type",
});
- cases.add("float literal too small error (denormal)",
+ ctx.objErrStage1("float literal too small error (denormal)",
\\comptime {
\\ const a = 0x1.0p-19000;
+ \\ _ = a;
\\}
, &[_][]const u8{
"tmp.zig:2:15: error: float literal out of range of any type",
});
- cases.add("explicit cast float literal to integer when there is a fraction component",
+ ctx.objErrStage1("explicit cast float literal to integer when there is a fraction component",
\\export fn entry() i32 {
\\ return @as(i32, 12.34);
\\}
@@ -6969,7 +7188,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:21: error: fractional component prevents float value 12.340000 from being casted to type 'i32'",
});
- cases.add("non pointer given to @ptrToInt",
+ ctx.objErrStage1("non pointer given to @ptrToInt",
\\export fn entry(x: i32) usize {
\\ return @ptrToInt(x);
\\}
@@ -6977,23 +7196,25 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:22: error: expected pointer, found 'i32'",
});
- cases.add("@shlExact shifts out 1 bits",
+ ctx.objErrStage1("@shlExact shifts out 1 bits",
\\comptime {
\\ const x = @shlExact(@as(u8, 0b01010101), 2);
+ \\ _ = x;
\\}
, &[_][]const u8{
"tmp.zig:2:15: error: operation caused overflow",
});
- cases.add("@shrExact shifts out 1 bits",
+ ctx.objErrStage1("@shrExact shifts out 1 bits",
\\comptime {
\\ const x = @shrExact(@as(u8, 0b10101010), 2);
+ \\ _ = x;
\\}
, &[_][]const u8{
"tmp.zig:2:15: error: exact shift shifted out 1 bits",
});
- cases.add("shifting without int type or comptime known",
+ ctx.objErrStage1("shifting without int type or comptime known",
\\export fn entry(x: u8) u8 {
\\ return 0x11 << x;
\\}
@@ -7001,7 +7222,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:17: error: LHS of shift must be a fixed-width integer type, or RHS must be compile-time known",
});
- cases.add("shifting RHS is log2 of LHS int bit width",
+ ctx.objErrStage1("shifting RHS is log2 of LHS int bit width",
\\export fn entry(x: u8, y: u8) u8 {
\\ return x << y;
\\}
@@ -7009,16 +7230,17 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:17: error: expected type 'u3', found 'u8'",
});
- cases.add("globally shadowing a primitive type",
+ ctx.objErrStage1("globally shadowing a primitive type",
\\const u16 = u8;
\\export fn entry() void {
\\ const a: u16 = 300;
+ \\ _ = a;
\\}
, &[_][]const u8{
"tmp.zig:1:1: error: declaration shadows primitive type 'u16'",
});
- cases.add("implicitly increasing pointer alignment",
+ ctx.objErrStage1("implicitly increasing pointer alignment",
\\const Foo = packed struct {
\\ a: u8,
\\ b: u32,
@@ -7036,7 +7258,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:8:13: error: expected type '*u32', found '*align(1) u32'",
});
- cases.add("implicitly increasing slice alignment",
+ ctx.objErrStage1("implicitly increasing slice alignment",
\\const Foo = packed struct {
\\ a: u8,
\\ b: u32,
@@ -7057,7 +7279,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:9:26: note: '*[1]u32' has alignment 4",
});
- cases.add("increase pointer alignment in @ptrCast",
+ ctx.objErrStage1("increase pointer alignment in @ptrCast",
\\export fn entry() u32 {
\\ var bytes: [4]u8 = [_]u8{0x01, 0x02, 0x03, 0x04};
\\ const ptr = @ptrCast(*u32, &bytes[0]);
@@ -7069,7 +7291,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:26: note: '*u32' has alignment 4",
});
- cases.add("@alignCast expects pointer or slice",
+ ctx.objErrStage1("@alignCast expects pointer or slice",
\\export fn entry() void {
\\ @alignCast(4, @as(u32, 3));
\\}
@@ -7077,7 +7299,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:19: error: expected pointer or slice, found 'u32'",
});
- cases.add("passing an under-aligned function pointer",
+ ctx.objErrStage1("passing an under-aligned function pointer",
\\export fn entry() void {
\\ testImplicitlyDecreaseFnAlign(alignedSmall, 1234);
\\}
@@ -7089,7 +7311,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:35: error: expected type 'fn() align(8) i32', found 'fn() align(4) i32'",
});
- cases.add("passing a not-aligned-enough pointer to cmpxchg",
+ ctx.objErrStage1("passing a not-aligned-enough pointer to cmpxchg",
\\const AtomicOrder = @import("std").builtin.AtomicOrder;
\\export fn entry() bool {
\\ var x: i32 align(1) = 1234;
@@ -7100,15 +7322,16 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:4:32: error: expected type '*i32', found '*align(1) i32'",
});
- cases.add("wrong size to an array literal",
+ ctx.objErrStage1("wrong size to an array literal",
\\comptime {
\\ const array = [2]u8{1, 2, 3};
+ \\ _ = array;
\\}
, &[_][]const u8{
"tmp.zig:2:31: error: index 2 outside array of size 2",
});
- cases.add("wrong pointer coerced to pointer to opaque {}",
+ ctx.objErrStage1("wrong pointer coerced to pointer to opaque {}",
\\const Derp = opaque {};
\\extern fn bar(d: *Derp) void;
\\export fn foo() void {
@@ -7119,49 +7342,57 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:5:9: error: expected type '*Derp', found '*c_void'",
});
- cases.add("non-const variables of things that require const variables",
+ ctx.objErrStage1("non-const variables of things that require const variables",
\\export fn entry1() void {
\\ var m2 = &2;
+ \\ _ = m2;
\\}
\\export fn entry2() void {
\\ var a = undefined;
+ \\ _ = a;
\\}
\\export fn entry3() void {
\\ var b = 1;
+ \\ _ = b;
\\}
\\export fn entry4() void {
\\ var c = 1.0;
+ \\ _ = c;
\\}
\\export fn entry5() void {
\\ var d = null;
+ \\ _ = d;
\\}
\\export fn entry6(opaque_: *Opaque) void {
\\ var e = opaque_.*;
+ \\ _ = e;
\\}
\\export fn entry7() void {
\\ var f = i32;
+ \\ _ = f;
\\}
\\export fn entry8() void {
\\ var h = (Foo {}).bar;
+ \\ _ = h;
\\}
\\const Opaque = opaque {};
\\const Foo = struct {
- \\ fn bar(self: *const Foo) void {}
+ \\ fn bar(self: *const Foo) void {_ = self;}
\\};
, &[_][]const u8{
"tmp.zig:2:4: error: variable of type '*const comptime_int' must be const or comptime",
- "tmp.zig:5:4: error: variable of type '(undefined)' must be const or comptime",
- "tmp.zig:8:4: error: variable of type 'comptime_int' must be const or comptime",
- "tmp.zig:8:4: note: to modify this variable at runtime, it must be given an explicit fixed-size number type",
- "tmp.zig:11:4: error: variable of type 'comptime_float' must be const or comptime",
- "tmp.zig:11:4: note: to modify this variable at runtime, it must be given an explicit fixed-size number type",
- "tmp.zig:14:4: error: variable of type '(null)' must be const or comptime",
- "tmp.zig:17:4: error: variable of type 'Opaque' not allowed",
- "tmp.zig:20:4: error: variable of type 'type' must be const or comptime",
- "tmp.zig:23:4: error: variable of type '(bound fn(*const Foo) void)' must be const or comptime",
+ "tmp.zig:6:4: error: variable of type '(undefined)' must be const or comptime",
+ "tmp.zig:10:4: error: variable of type 'comptime_int' must be const or comptime",
+ "tmp.zig:10:4: note: to modify this variable at runtime, it must be given an explicit fixed-size number type",
+ "tmp.zig:14:4: error: variable of type 'comptime_float' must be const or comptime",
+ "tmp.zig:14:4: note: to modify this variable at runtime, it must be given an explicit fixed-size number type",
+ "tmp.zig:18:4: error: variable of type '(null)' must be const or comptime",
+ "tmp.zig:22:4: error: variable of type 'Opaque' not allowed",
+ "tmp.zig:26:4: error: variable of type 'type' must be const or comptime",
+ "tmp.zig:30:4: error: variable of type '(bound fn(*const Foo) void)' must be const or comptime",
});
- cases.add("variable with type 'noreturn'",
+ ctx.objErrStage1("variable with type 'noreturn'",
\\export fn entry9() void {
\\ var z: noreturn = return;
\\}
@@ -7170,7 +7401,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:23: note: control flow is diverted here",
});
- cases.add("wrong types given to atomic order args in cmpxchg",
+ ctx.objErrStage1("wrong types given to atomic order args in cmpxchg",
\\export fn entry() void {
\\ var x: i32 = 1234;
\\ while (!@cmpxchgWeak(i32, &x, 1234, 5678, @as(u32, 1234), @as(u32, 1234))) {}
@@ -7179,7 +7410,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:47: error: expected type 'std.builtin.AtomicOrder', found 'u32'",
});
- cases.add("wrong types given to @export",
+ ctx.objErrStage1("wrong types given to @export",
\\fn entry() callconv(.C) void { }
\\comptime {
\\ @export(entry, .{.name = "entry", .linkage = @as(u32, 1234) });
@@ -7188,7 +7419,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:59: error: expected type 'std.builtin.GlobalLinkage', found 'comptime_int'",
});
- cases.add("struct with invalid field",
+ ctx.objErrStage1("struct with invalid field",
\\const std = @import("std",);
\\const Allocator = std.mem.Allocator;
\\const ArrayList = std.ArrayList;
@@ -7211,12 +7442,13 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ .text = MdText.init(&std.testing.allocator),
\\ .weight = HeaderWeight.H1,
\\ };
+ \\ _ = a;
\\}
, &[_][]const u8{
"tmp.zig:14:17: error: use of undeclared identifier 'HeaderValue'",
});
- cases.add("@setAlignStack outside function",
+ ctx.objErrStage1("@setAlignStack outside function",
\\comptime {
\\ @setAlignStack(16);
\\}
@@ -7224,7 +7456,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:5: error: @setAlignStack outside function",
});
- cases.add("@setAlignStack in naked function",
+ ctx.objErrStage1("@setAlignStack in naked function",
\\export fn entry() callconv(.Naked) void {
\\ @setAlignStack(16);
\\}
@@ -7232,7 +7464,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:5: error: @setAlignStack in naked function",
});
- cases.add("@setAlignStack in inline function",
+ ctx.objErrStage1("@setAlignStack in inline function",
\\export fn entry() void {
\\ foo();
\\}
@@ -7243,7 +7475,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:5:5: error: @setAlignStack in inline function",
});
- cases.add("@setAlignStack set twice",
+ ctx.objErrStage1("@setAlignStack set twice",
\\export fn entry() void {
\\ @setAlignStack(16);
\\ @setAlignStack(16);
@@ -7253,7 +7485,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:5: note: first set here",
});
- cases.add("@setAlignStack too big",
+ ctx.objErrStage1("@setAlignStack too big",
\\export fn entry() void {
\\ @setAlignStack(511 + 1);
\\}
@@ -7261,7 +7493,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:5: error: attempt to @setAlignStack(512); maximum is 256",
});
- cases.add("storing runtime value in compile time variable then using it",
+ ctx.objErrStage1("storing runtime value in compile time variable then using it",
\\const Mode = @import("std").builtin.Mode;
\\
\\fn Free(comptime filename: []const u8) TestCase {
@@ -7307,7 +7539,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:37:29: error: cannot store runtime value in compile time variable",
});
- cases.add("invalid legacy unicode escape",
+ ctx.objErrStage1("invalid legacy unicode escape",
\\export fn entry() void {
\\ const a = '\U1234';
\\}
@@ -7315,7 +7547,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:17: error: invalid character: 'U'",
});
- cases.add("invalid empty unicode escape",
+ ctx.objErrStage1("invalid empty unicode escape",
\\export fn entry() void {
\\ const a = '\u{}';
\\}
@@ -7323,21 +7555,20 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:19: error: empty unicode escape sequence",
});
- cases.add("non-printable invalid character", "\xff\xfe" ++
- \\fn test() bool {\r
- \\ true\r
- \\}
- , &[_][]const u8{
+ ctx.objErrStage1("non-printable invalid character", "\xff\xfe" ++
+ "fn foo() bool {\r\n" ++
+ " return true;\r\n" ++
+ "}\r\n", &[_][]const u8{
"tmp.zig:1:1: error: invalid character: '\\xff'",
});
- cases.add("non-printable invalid character with escape alternative", "fn test() bool {\n" ++
- "\ttrue\n" ++
+ ctx.objErrStage1("non-printable invalid character with escape alternative", "fn foo() bool {\n" ++
+ "\treturn true;\n" ++
"}\n", &[_][]const u8{
"tmp.zig:2:1: error: invalid character: '\\t'",
});
- cases.add("calling var args extern function, passing array instead of pointer",
+ ctx.objErrStage1("calling var args extern function, passing array instead of pointer",
\\export fn entry() void {
\\ foo("hello".*,);
\\}
@@ -7346,7 +7577,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:16: error: expected type '*const u8', found '[5:0]u8'",
});
- cases.add("constant inside comptime function has compile error",
+ ctx.objErrStage1("constant inside comptime function has compile error",
\\const ContextAllocator = MemoryPool(usize);
\\
\\pub fn MemoryPool(comptime T: type) type {
@@ -7361,12 +7592,12 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var allocator: ContextAllocator = undefined;
\\}
, &[_][]const u8{
- "tmp.zig:4:25: error: aoeu",
- "tmp.zig:1:36: note: referenced here",
- "tmp.zig:12:20: note: referenced here",
+ "tmp.zig:4:5: error: unreachable code",
+ "tmp.zig:4:25: note: control flow is diverted here",
+ "tmp.zig:12:9: error: unused local variable",
});
- cases.add("specify enum tag type that is too small",
+ ctx.objErrStage1("specify enum tag type that is too small",
\\const Small = enum (u2) {
\\ One,
\\ Two,
@@ -7377,12 +7608,13 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\export fn entry() void {
\\ var x = Small.One;
+ \\ _ = x;
\\}
, &[_][]const u8{
"tmp.zig:6:5: error: enumeration value 4 too large for type 'u2'",
});
- cases.add("specify non-integer enum tag type",
+ ctx.objErrStage1("specify non-integer enum tag type",
\\const Small = enum (f32) {
\\ One,
\\ Two,
@@ -7391,12 +7623,13 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\export fn entry() void {
\\ var x = Small.One;
+ \\ _ = x;
\\}
, &[_][]const u8{
"tmp.zig:1:21: error: expected integer, found 'f32'",
});
- cases.add("implicitly casting enum to tag type",
+ ctx.objErrStage1("implicitly casting enum to tag type",
\\const Small = enum(u2) {
\\ One,
\\ Two,
@@ -7406,12 +7639,13 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\export fn entry() void {
\\ var x: u2 = Small.Two;
+ \\ _ = x;
\\}
, &[_][]const u8{
"tmp.zig:9:22: error: expected type 'u2', found 'Small'",
});
- cases.add("explicitly casting non tag type to enum",
+ ctx.objErrStage1("explicitly casting non tag type to enum",
\\const Small = enum(u2) {
\\ One,
\\ Two,
@@ -7422,24 +7656,26 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\export fn entry() void {
\\ var y = @as(u3, 3);
\\ var x = @intToEnum(Small, y);
+ \\ _ = x;
\\}
, &[_][]const u8{
"tmp.zig:10:31: error: expected type 'u2', found 'u3'",
});
- cases.add("union fields with value assignments",
+ ctx.objErrStage1("union fields with value assignments",
\\const MultipleChoice = union {
\\ A: i32 = 20,
\\};
\\export fn entry() void {
\\ var x: MultipleChoice = undefined;
+ \\ _ = x;
\\}
, &[_][]const u8{
"tmp.zig:2:14: error: untagged union field assignment",
"tmp.zig:1:24: note: consider 'union(enum)' here",
});
- cases.add("enum with 0 fields",
+ ctx.objErrStage1("enum with 0 fields",
\\const Foo = enum {};
\\export fn entry() usize {
\\ return @sizeOf(Foo);
@@ -7448,16 +7684,16 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:1:13: error: enums must have 1 or more fields",
});
- cases.add("union with 0 fields",
+ ctx.objErrStage1("union with 0 fields",
\\const Foo = union {};
\\export fn entry() usize {
\\ return @sizeOf(Foo);
\\}
, &[_][]const u8{
- "tmp.zig:1:13: error: unions must have 1 or more fields",
+ "tmp.zig:1:13: error: union declarations must have at least one tag",
});
- cases.add("enum value already taken",
+ ctx.objErrStage1("enum value already taken",
\\const MultipleChoice = enum(u32) {
\\ A = 20,
\\ B = 40,
@@ -7467,13 +7703,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\};
\\export fn entry() void {
\\ var x = MultipleChoice.C;
+ \\ _ = x;
\\}
, &[_][]const u8{
"tmp.zig:6:5: error: enum tag value 60 already taken",
"tmp.zig:4:5: note: other occurrence here",
});
- cases.add("union with specified enum omits field",
+ ctx.objErrStage1("union with specified enum omits field",
\\const Letter = enum {
\\ A,
\\ B,
@@ -7491,29 +7728,31 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:4:5: note: declared here",
});
- cases.add("non-integer tag type to automatic union enum",
+ ctx.objErrStage1("non-integer tag type to automatic union enum",
\\const Foo = union(enum(f32)) {
\\ A: i32,
\\};
\\export fn entry() void {
\\ const x = @typeInfo(Foo).Union.tag_type.?;
+ \\ _ = x;
\\}
, &[_][]const u8{
"tmp.zig:1:24: error: expected integer tag type, found 'f32'",
});
- cases.add("non-enum tag type passed to union",
+ ctx.objErrStage1("non-enum tag type passed to union",
\\const Foo = union(u32) {
\\ A: i32,
\\};
\\export fn entry() void {
\\ const x = @typeInfo(Foo).Union.tag_type.?;
+ \\ _ = x;
\\}
, &[_][]const u8{
"tmp.zig:1:19: error: expected enum tag type, found 'u32'",
});
- cases.add("union auto-enum value already taken",
+ ctx.objErrStage1("union auto-enum value already taken",
\\const MultipleChoice = union(enum(u32)) {
\\ A = 20,
\\ B = 40,
@@ -7523,13 +7762,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\};
\\export fn entry() void {
\\ var x = MultipleChoice { .C = {} };
+ \\ _ = x;
\\}
, &[_][]const u8{
"tmp.zig:6:9: error: enum tag value 60 already taken",
"tmp.zig:4:9: note: other occurrence here",
});
- cases.add("union enum field does not match enum",
+ ctx.objErrStage1("union enum field does not match enum",
\\const Letter = enum {
\\ A,
\\ B,
@@ -7543,13 +7783,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\};
\\export fn entry() void {
\\ var a = Payload {.A = 1234};
+ \\ _ = a;
\\}
, &[_][]const u8{
"tmp.zig:10:5: error: enum field not found: 'D'",
"tmp.zig:1:16: note: enum declared here",
});
- cases.add("field type supplied in an enum",
+ ctx.objErrStage1("field type supplied in an enum",
\\const Letter = enum {
\\ A: void,
\\ B,
@@ -7557,35 +7798,38 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\};
\\export fn entry() void {
\\ var b = Letter.B;
+ \\ _ = b;
\\}
, &[_][]const u8{
"tmp.zig:2:8: error: structs and unions, not enums, support field types",
"tmp.zig:1:16: note: consider 'union(enum)' here",
});
- cases.add("struct field missing type",
+ ctx.objErrStage1("struct field missing type",
\\const Letter = struct {
\\ A,
\\};
\\export fn entry() void {
\\ var a = Letter { .A = {} };
+ \\ _ = a;
\\}
, &[_][]const u8{
"tmp.zig:2:5: error: struct field missing type",
});
- cases.add("extern union field missing type",
+ ctx.objErrStage1("extern union field missing type",
\\const Letter = extern union {
\\ A,
\\};
\\export fn entry() void {
\\ var a = Letter { .A = {} };
+ \\ _ = a;
\\}
, &[_][]const u8{
"tmp.zig:2:5: error: union field missing type",
});
- cases.add("extern union given enum tag type",
+ ctx.objErrStage1("extern union given enum tag type",
\\const Letter = enum {
\\ A,
\\ B,
@@ -7598,12 +7842,13 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\};
\\export fn entry() void {
\\ var a = Payload { .A = 1234 };
+ \\ _ = a;
\\}
, &[_][]const u8{
"tmp.zig:6:30: error: extern union does not support enum tag type",
});
- cases.add("packed union given enum tag type",
+ ctx.objErrStage1("packed union given enum tag type",
\\const Letter = enum {
\\ A,
\\ B,
@@ -7616,12 +7861,13 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\};
\\export fn entry() void {
\\ var a = Payload { .A = 1234 };
+ \\ _ = a;
\\}
, &[_][]const u8{
"tmp.zig:6:30: error: packed union does not support enum tag type",
});
- cases.add("packed union with automatic layout field",
+ ctx.objErrStage1("packed union with automatic layout field",
\\const Foo = struct {
\\ a: u32,
\\ b: f32,
@@ -7632,12 +7878,13 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\};
\\export fn entry() void {
\\ var a = Payload { .B = true };
+ \\ _ = a;
\\}
, &[_][]const u8{
"tmp.zig:6:5: error: non-packed, non-extern struct 'Foo' not allowed in packed union; no guaranteed in-memory representation",
});
- cases.add("switch on union with no attached enum",
+ ctx.objErrStage1("switch on union with no attached enum",
\\const Payload = union {
\\ A: i32,
\\ B: f64,
@@ -7658,20 +7905,21 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:1:17: note: consider 'union(enum)' here",
});
- cases.add("enum in field count range but not matching tag",
+ ctx.objErrStage1("enum in field count range but not matching tag",
\\const Foo = enum(u32) {
\\ A = 10,
\\ B = 11,
\\};
\\export fn entry() void {
\\ var x = @intToEnum(Foo, 0);
+ \\ _ = x;
\\}
, &[_][]const u8{
"tmp.zig:6:13: error: enum 'Foo' has no tag matching integer value 0",
"tmp.zig:1:13: note: 'Foo' declared here",
});
- cases.add("comptime cast enum to union but field has payload",
+ ctx.objErrStage1("comptime cast enum to union but field has payload",
\\const Letter = enum { A, B, C };
\\const Value = union(Letter) {
\\ A: i32,
@@ -7680,13 +7928,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\};
\\export fn entry() void {
\\ var x: Value = Letter.A;
+ \\ _ = x;
\\}
, &[_][]const u8{
"tmp.zig:8:26: error: cast to union 'Value' must initialize 'i32' field 'A'",
"tmp.zig:3:5: note: field 'A' declared here",
});
- cases.add("runtime cast to union which has non-void fields",
+ ctx.objErrStage1("runtime cast to union which has non-void fields",
\\const Letter = enum { A, B, C };
\\const Value = union(Letter) {
\\ A: i32,
@@ -7698,13 +7947,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
\\fn foo(l: Letter) void {
\\ var x: Value = l;
+ \\ _ = x;
\\}
, &[_][]const u8{
"tmp.zig:11:20: error: runtime cast to union 'Value' which has non-void fields",
"tmp.zig:3:5: note: field 'A' has type 'i32'",
});
- cases.add("taking byte offset of void field in struct",
+ ctx.objErrStage1("taking byte offset of void field in struct",
\\const Empty = struct {
\\ val: void,
\\};
@@ -7715,7 +7965,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:5:42: error: zero-bit field 'val' in struct 'Empty' has no offset",
});
- cases.add("taking bit offset of void field in struct",
+ ctx.objErrStage1("taking bit offset of void field in struct",
\\const Empty = struct {
\\ val: void,
\\};
@@ -7726,7 +7976,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:5:45: error: zero-bit field 'val' in struct 'Empty' has no offset",
});
- cases.add("invalid union field access in comptime",
+ ctx.objErrStage1("invalid union field access in comptime",
\\const Foo = union {
\\ Bar: u8,
\\ Baz: void,
@@ -7739,7 +7989,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:7:24: error: accessing union field 'Bar' while field 'Baz' is set",
});
- cases.add("unsupported modifier at start of asm output constraint",
+ ctx.objErrStage1("unsupported modifier at start of asm output constraint",
\\export fn foo() void {
\\ var bar: u32 = 3;
\\ asm volatile ("" : [baz]"+r"(bar) : : "");
@@ -7748,7 +7998,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:3:5: error: invalid modifier starting output constraint for 'baz': '+', only '=' is supported. Compiler TODO: see https://github.com/ziglang/zig/issues/215",
});
- cases.add("comptime_int in asm input",
+ ctx.objErrStage1("comptime_int in asm input",
\\export fn foo() void {
\\ asm volatile ("" : : [bar]"r"(3) : "");
\\}
@@ -7756,7 +8006,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:35: error: expected sized integer or sized float, found comptime_int",
});
- cases.add("comptime_float in asm input",
+ ctx.objErrStage1("comptime_float in asm input",
\\export fn foo() void {
\\ asm volatile ("" : : [bar]"r"(3.17) : "");
\\}
@@ -7764,7 +8014,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:35: error: expected sized integer or sized float, found comptime_float",
});
- cases.add("runtime assignment to comptime struct type",
+ ctx.objErrStage1("runtime assignment to comptime struct type",
\\const Foo = struct {
\\ Bar: u8,
\\ Baz: type,
@@ -7772,12 +8022,13 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\export fn f() void {
\\ var x: u8 = 0;
\\ const foo = Foo { .Bar = x, .Baz = u8 };
+ \\ _ = foo;
\\}
, &[_][]const u8{
"tmp.zig:7:23: error: unable to evaluate constant expression",
});
- cases.add("runtime assignment to comptime union type",
+ ctx.objErrStage1("runtime assignment to comptime union type",
\\const Foo = union {
\\ Bar: u8,
\\ Baz: type,
@@ -7785,16 +8036,18 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\export fn f() void {
\\ var x: u8 = 0;
\\ const foo = Foo { .Bar = x };
+ \\ _ = foo;
\\}
, &[_][]const u8{
"tmp.zig:7:23: error: unable to evaluate constant expression",
});
- cases.addTest("@shuffle with selected index past first vector length",
+ ctx.testErrStage1("@shuffle with selected index past first vector length",
\\export fn entry() void {
\\ const v: @import("std").meta.Vector(4, u32) = [4]u32{ 10, 11, 12, 13 };
\\ const x: @import("std").meta.Vector(4, u32) = [4]u32{ 14, 15, 16, 17 };
\\ var z = @shuffle(u32, v, x, [8]i32{ 0, 1, 2, 3, 7, 6, 5, 4 });
+ \\ _ = z;
\\}
, &[_][]const u8{
"tmp.zig:4:39: error: mask index '4' has out-of-bounds selection",
@@ -7802,27 +8055,29 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:4:30: note: selections from the second vector are specified with negative numbers",
});
- cases.addTest("nested vectors",
+ ctx.testErrStage1("nested vectors",
\\export fn entry() void {
\\ const V1 = @import("std").meta.Vector(4, u8);
\\ const V2 = @Type(@import("std").builtin.TypeInfo{ .Vector = .{ .len = 4, .child = V1 } });
\\ var v: V2 = undefined;
+ \\ _ = v;
\\}
, &[_][]const u8{
"tmp.zig:3:53: error: vector element type must be integer, float, bool, or pointer; '@Vector(4, u8)' is invalid",
"tmp.zig:3:16: note: referenced here",
});
- cases.addTest("bad @splat type",
+ ctx.testErrStage1("bad @splat type",
\\export fn entry() void {
\\ const c = 4;
\\ var v = @splat(4, c);
+ \\ _ = v;
\\}
, &[_][]const u8{
"tmp.zig:3:23: error: vector element type must be integer, float, bool, or pointer; 'comptime_int' is invalid",
});
- cases.add("compileLog of tagged enum doesn't crash the compiler",
+ ctx.objErrStage1("compileLog of tagged enum doesn't crash the compiler",
\\const Bar = union(enum(u32)) {
\\ X: i32 = 1
\\};
@@ -7838,7 +8093,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:6:5: error: found compile log statement",
});
- cases.add("attempted implicit cast from *const T to *[1]T",
+ ctx.objErrStage1("attempted implicit cast from *const T to *[1]T",
\\export fn entry(byte: u8) void {
\\ const w: i32 = 1234;
\\ var x: *const i32 = &w;
@@ -7850,16 +8105,17 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:4:22: note: cast discards const qualifier",
});
- cases.add("attempted implicit cast from *const T to []T",
+ ctx.objErrStage1("attempted implicit cast from *const T to []T",
\\export fn entry() void {
\\ const u: u32 = 42;
\\ const x: []u32 = &u;
+ \\ _ = x;
\\}
, &[_][]const u8{
"tmp.zig:3:23: error: expected type '[]u32', found '*const u32'",
});
- cases.add("for loop body expression ignored",
+ ctx.objErrStage1("for loop body expression ignored",
\\fn returns() usize {
\\ return 2;
\\}
@@ -7875,7 +8131,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:9:30: error: expression value is ignored",
});
- cases.add("aligned variable of zero-bit type",
+ ctx.objErrStage1("aligned variable of zero-bit type",
\\export fn f() void {
\\ var s: struct {} align(4) = undefined;
\\}
@@ -7883,7 +8139,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:5: error: variable 's' of zero-bit type 'struct:2:12' has no in-memory representation, it cannot be aligned",
});
- cases.add("function returning opaque type",
+ ctx.objErrStage1("function returning opaque type",
\\const FooType = opaque {};
\\export fn bar() !FooType {
\\ return error.InvalidValue;
@@ -7901,7 +8157,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:8:18: error: Undefined return type '(undefined)' not allowed",
});
- cases.add("generic function returning opaque type",
+ ctx.objErrStage1("generic function returning opaque type",
\\const FooType = opaque {};
\\fn generic(comptime T: type) !T {
\\ return undefined;
@@ -7925,22 +8181,24 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:1: note: function declared here",
});
- cases.add("function parameter is opaque",
+ ctx.objErrStage1("function parameter is opaque",
\\const FooType = opaque {};
\\export fn entry1() void {
\\ const someFuncPtr: fn (FooType) void = undefined;
+ \\ _ = someFuncPtr;
\\}
\\
\\export fn entry2() void {
\\ const someFuncPtr: fn (@TypeOf(null)) void = undefined;
+ \\ _ = someFuncPtr;
\\}
\\
- \\fn foo(p: FooType) void {}
+ \\fn foo(p: FooType) void {_ = p;}
\\export fn entry3() void {
\\ _ = foo;
\\}
\\
- \\fn bar(p: @TypeOf(null)) void {}
+ \\fn bar(p: @TypeOf(null)) void {_ = p;}
\\export fn entry4() void {
\\ _ = bar;
\\}
@@ -7951,30 +8209,34 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:15:11: error: parameter of type '(null)' not allowed",
});
- cases.add( // fixed bug #2032
+ ctx.objErrStage1( // fixed bug #2032
"compile diagnostic string for top level decl type",
\\export fn entry() void {
\\ var foo: u32 = @This(){};
+ \\ _ = foo;
\\}
, &[_][]const u8{
"tmp.zig:2:27: error: type 'u32' does not support array initialization",
});
- cases.add("issue #2687: coerce from undefined array pointer to slice",
+ ctx.objErrStage1("issue #2687: coerce from undefined array pointer to slice",
\\export fn foo1() void {
\\ const a: *[1]u8 = undefined;
\\ var b: []u8 = a;
+ \\ _ = b;
\\}
\\export fn foo2() void {
\\ comptime {
\\ var a: *[1]u8 = undefined;
\\ var b: []u8 = a;
+ \\ _ = b;
\\ }
\\}
\\export fn foo3() void {
\\ comptime {
\\ const a: *[1]u8 = undefined;
\\ var b: []u8 = a;
+ \\ _ = b;
\\ }
\\}
, &[_][]const u8{
@@ -7983,14 +8245,16 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:14:23: error: use of undefined value here causes undefined behavior",
});
- cases.add("issue #3818: bitcast from parray/slice to u16",
+ ctx.objErrStage1("issue #3818: bitcast from parray/slice to u16",
\\export fn foo1() void {
\\ var bytes = [_]u8{1, 2};
\\ const word: u16 = @bitCast(u16, bytes[0..]);
+ \\ _ = word;
\\}
\\export fn foo2() void {
\\ var bytes: []const u8 = &[_]u8{1, 2};
\\ const word: u16 = @bitCast(u16, bytes);
+ \\ _ = word;
\\}
, &[_][]const u8{
"tmp.zig:3:42: error: unable to @bitCast from pointer type '*[2]u8'",
@@ -7999,7 +8263,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
});
// issue #7810
- cases.add("comptime slice-len increment beyond bounds",
+ ctx.objErrStage1("comptime slice-len increment beyond bounds",
\\export fn foo_slice_len_increment_beyond_bounds() void {
\\ comptime {
\\ var buf_storage: [8]u8 = undefined;
@@ -8012,11 +8276,12 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
":6:12: error: out of bounds slice",
});
- cases.add("comptime slice-sentinel is out of bounds (unterminated)",
+ ctx.objErrStage1("comptime slice-sentinel is out of bounds (unterminated)",
\\export fn foo_array() void {
\\ comptime {
\\ var target = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
\\ const slice = target[0..14 :0];
+ \\ _ = slice;
\\ }
\\}
\\export fn foo_ptr_array() void {
@@ -8024,6 +8289,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
\\ var target = &buf;
\\ const slice = target[0..14 :0];
+ \\ _ = slice;
\\ }
\\}
\\export fn foo_vector_ConstPtrSpecialBaseArray() void {
@@ -8031,6 +8297,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
\\ var target: [*]u8 = &buf;
\\ const slice = target[0..14 :0];
+ \\ _ = slice;
\\ }
\\}
\\export fn foo_vector_ConstPtrSpecialRef() void {
@@ -8038,6 +8305,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
\\ var target: [*]u8 = @ptrCast([*]u8, &buf);
\\ const slice = target[0..14 :0];
+ \\ _ = slice;
\\ }
\\}
\\export fn foo_cvector_ConstPtrSpecialBaseArray() void {
@@ -8045,6 +8313,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
\\ var target: [*c]u8 = &buf;
\\ const slice = target[0..14 :0];
+ \\ _ = slice;
\\ }
\\}
\\export fn foo_cvector_ConstPtrSpecialRef() void {
@@ -8052,6 +8321,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
\\ var target: [*c]u8 = @ptrCast([*c]u8, &buf);
\\ const slice = target[0..14 :0];
+ \\ _ = slice;
\\ }
\\}
\\export fn foo_slice() void {
@@ -8059,6 +8329,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
\\ var target: []u8 = &buf;
\\ const slice = target[0..14 :0];
+ \\ _ = slice;
\\ }
\\}
, &[_][]const u8{
@@ -8071,11 +8342,12 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
":46:29: error: slice-sentinel is out of bounds",
});
- cases.add("comptime slice-sentinel is out of bounds (terminated)",
+ ctx.objErrStage1("comptime slice-sentinel is out of bounds (terminated)",
\\export fn foo_array() void {
\\ comptime {
\\ var target = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
\\ const slice = target[0..15 :1];
+ \\ _ = slice;
\\ }
\\}
\\export fn foo_ptr_array() void {
@@ -8083,6 +8355,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
\\ var target = &buf;
\\ const slice = target[0..15 :0];
+ \\ _ = slice;
\\ }
\\}
\\export fn foo_vector_ConstPtrSpecialBaseArray() void {
@@ -8090,6 +8363,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
\\ var target: [*]u8 = &buf;
\\ const slice = target[0..15 :0];
+ \\ _ = slice;
\\ }
\\}
\\export fn foo_vector_ConstPtrSpecialRef() void {
@@ -8097,6 +8371,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
\\ var target: [*]u8 = @ptrCast([*]u8, &buf);
\\ const slice = target[0..15 :0];
+ \\ _ = slice;
\\ }
\\}
\\export fn foo_cvector_ConstPtrSpecialBaseArray() void {
@@ -8104,6 +8379,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
\\ var target: [*c]u8 = &buf;
\\ const slice = target[0..15 :0];
+ \\ _ = slice;
\\ }
\\}
\\export fn foo_cvector_ConstPtrSpecialRef() void {
@@ -8111,6 +8387,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
\\ var target: [*c]u8 = @ptrCast([*c]u8, &buf);
\\ const slice = target[0..15 :0];
+ \\ _ = slice;
\\ }
\\}
\\export fn foo_slice() void {
@@ -8118,6 +8395,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
\\ var target: []u8 = &buf;
\\ const slice = target[0..15 :0];
+ \\ _ = slice;
\\ }
\\}
, &[_][]const u8{
@@ -8130,11 +8408,12 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
":46:29: error: out of bounds slice",
});
- cases.add("comptime slice-sentinel does not match memory at target index (unterminated)",
+ ctx.objErrStage1("comptime slice-sentinel does not match memory at target index (unterminated)",
\\export fn foo_array() void {
\\ comptime {
\\ var target = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
\\ const slice = target[0..3 :0];
+ \\ _ = slice;
\\ }
\\}
\\export fn foo_ptr_array() void {
@@ -8142,6 +8421,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
\\ var target = &buf;
\\ const slice = target[0..3 :0];
+ \\ _ = slice;
\\ }
\\}
\\export fn foo_vector_ConstPtrSpecialBaseArray() void {
@@ -8149,6 +8429,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
\\ var target: [*]u8 = &buf;
\\ const slice = target[0..3 :0];
+ \\ _ = slice;
\\ }
\\}
\\export fn foo_vector_ConstPtrSpecialRef() void {
@@ -8156,6 +8437,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
\\ var target: [*]u8 = @ptrCast([*]u8, &buf);
\\ const slice = target[0..3 :0];
+ \\ _ = slice;
\\ }
\\}
\\export fn foo_cvector_ConstPtrSpecialBaseArray() void {
@@ -8163,6 +8445,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
\\ var target: [*c]u8 = &buf;
\\ const slice = target[0..3 :0];
+ \\ _ = slice;
\\ }
\\}
\\export fn foo_cvector_ConstPtrSpecialRef() void {
@@ -8170,6 +8453,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
\\ var target: [*c]u8 = @ptrCast([*c]u8, &buf);
\\ const slice = target[0..3 :0];
+ \\ _ = slice;
\\ }
\\}
\\export fn foo_slice() void {
@@ -8177,6 +8461,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var buf = [_]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
\\ var target: []u8 = &buf;
\\ const slice = target[0..3 :0];
+ \\ _ = slice;
\\ }
\\}
, &[_][]const u8{
@@ -8189,11 +8474,12 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
":46:29: error: slice-sentinel does not match memory at target index",
});
- cases.add("comptime slice-sentinel does not match memory at target index (terminated)",
+ ctx.objErrStage1("comptime slice-sentinel does not match memory at target index (terminated)",
\\export fn foo_array() void {
\\ comptime {
\\ var target = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
\\ const slice = target[0..3 :0];
+ \\ _ = slice;
\\ }
\\}
\\export fn foo_ptr_array() void {
@@ -8201,6 +8487,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
\\ var target = &buf;
\\ const slice = target[0..3 :0];
+ \\ _ = slice;
\\ }
\\}
\\export fn foo_vector_ConstPtrSpecialBaseArray() void {
@@ -8208,6 +8495,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
\\ var target: [*]u8 = &buf;
\\ const slice = target[0..3 :0];
+ \\ _ = slice;
\\ }
\\}
\\export fn foo_vector_ConstPtrSpecialRef() void {
@@ -8215,6 +8503,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
\\ var target: [*]u8 = @ptrCast([*]u8, &buf);
\\ const slice = target[0..3 :0];
+ \\ _ = slice;
\\ }
\\}
\\export fn foo_cvector_ConstPtrSpecialBaseArray() void {
@@ -8222,6 +8511,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
\\ var target: [*c]u8 = &buf;
\\ const slice = target[0..3 :0];
+ \\ _ = slice;
\\ }
\\}
\\export fn foo_cvector_ConstPtrSpecialRef() void {
@@ -8229,6 +8519,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
\\ var target: [*c]u8 = @ptrCast([*c]u8, &buf);
\\ const slice = target[0..3 :0];
+ \\ _ = slice;
\\ }
\\}
\\export fn foo_slice() void {
@@ -8236,6 +8527,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
\\ var target: []u8 = &buf;
\\ const slice = target[0..3 :0];
+ \\ _ = slice;
\\ }
\\}
, &[_][]const u8{
@@ -8248,11 +8540,12 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
":46:29: error: slice-sentinel does not match memory at target index",
});
- cases.add("comptime slice-sentinel does not match target-sentinel",
+ ctx.objErrStage1("comptime slice-sentinel does not match target-sentinel",
\\export fn foo_array() void {
\\ comptime {
\\ var target = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
\\ const slice = target[0..14 :255];
+ \\ _ = slice;
\\ }
\\}
\\export fn foo_ptr_array() void {
@@ -8260,6 +8553,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
\\ var target = &buf;
\\ const slice = target[0..14 :255];
+ \\ _ = slice;
\\ }
\\}
\\export fn foo_vector_ConstPtrSpecialBaseArray() void {
@@ -8267,6 +8561,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
\\ var target: [*]u8 = &buf;
\\ const slice = target[0..14 :255];
+ \\ _ = slice;
\\ }
\\}
\\export fn foo_vector_ConstPtrSpecialRef() void {
@@ -8274,6 +8569,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
\\ var target: [*]u8 = @ptrCast([*]u8, &buf);
\\ const slice = target[0..14 :255];
+ \\ _ = slice;
\\ }
\\}
\\export fn foo_cvector_ConstPtrSpecialBaseArray() void {
@@ -8281,6 +8577,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
\\ var target: [*c]u8 = &buf;
\\ const slice = target[0..14 :255];
+ \\ _ = slice;
\\ }
\\}
\\export fn foo_cvector_ConstPtrSpecialRef() void {
@@ -8288,6 +8585,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
\\ var target: [*c]u8 = @ptrCast([*c]u8, &buf);
\\ const slice = target[0..14 :255];
+ \\ _ = slice;
\\ }
\\}
\\export fn foo_slice() void {
@@ -8295,6 +8593,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var buf = [_:0]u8{ 'a', 'b', 'c', 'd' } ++ [_]u8{undefined} ** 10;
\\ var target: []u8 = &buf;
\\ const slice = target[0..14 :255];
+ \\ _ = slice;
\\ }
\\}
, &[_][]const u8{
@@ -8307,7 +8606,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
":46:29: error: slice-sentinel does not match target-sentinel",
});
- cases.add("issue #4207: coerce from non-terminated-slice to terminated-pointer",
+ ctx.objErrStage1("issue #4207: coerce from non-terminated-slice to terminated-pointer",
\\export fn foo() [*:0]const u8 {
\\ var buffer: [64]u8 = undefined;
\\ return buffer[0..];
@@ -8317,7 +8616,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
":3:18: note: destination pointer requires a terminating '0' sentinel",
});
- cases.add("issue #5221: invalid struct init type referenced by @typeInfo and passed into function",
+ ctx.objErrStage1("issue #5221: invalid struct init type referenced by @typeInfo and passed into function",
\\fn ignore(comptime param: anytype) void {}
\\
\\export fn foo() void {
@@ -8331,7 +8630,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
":5:28: error: expected type '[]u8', found '*const [3:0]u8'",
});
- cases.add("integer underflow error",
+ ctx.objErrStage1("integer underflow error",
\\export fn entry() void {
\\ _ = @intToPtr(*c_void, ~@as(usize, @import("std").math.maxInt(usize)) - 1);
\\}
@@ -8339,23 +8638,24 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
":2:75: error: operation caused overflow",
});
- cases.addCase(x: {
- var tc = cases.create("align(N) expr function pointers is a compile error",
+ {
+ const case = ctx.obj("align(N) expr function pointers is a compile error", .{
+ .cpu_arch = .wasm32,
+ .os_tag = .freestanding,
+ .abi = .none,
+ });
+ case.backend = .stage1;
+
+ case.addError(
\\export fn foo() align(1) void {
\\ return;
\\}
, &[_][]const u8{
"tmp.zig:1:23: error: align(N) expr is not allowed on function prototypes in wasm32/wasm64",
});
- tc.target = std.zig.CrossTarget{
- .cpu_arch = .wasm32,
- .os_tag = .freestanding,
- .abi = .none,
- };
- break :x tc;
- });
+ }
- cases.add("compare optional to non-optional with invalid types",
+ ctx.objErrStage1("compare optional to non-optional with invalid types",
\\export fn inconsistentChildType() void {
\\ var x: ?i32 = undefined;
\\ const y: comptime_int = 10;
@@ -8389,16 +8689,17 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
":22:12: note: operator not supported for type '[3]i32'",
});
- cases.add("slice cannot have its bytes reinterpreted",
+ ctx.objErrStage1("slice cannot have its bytes reinterpreted",
\\export fn foo() void {
\\ const bytes = [1]u8{ 0xfa } ** 16;
\\ var value = @ptrCast(*const []const u8, &bytes).*;
+ \\ _ = value;
\\}
, &[_][]const u8{
":3:52: error: slice '[]const u8' cannot have its bytes reinterpreted",
});
- cases.add("wasmMemorySize is a compile error in non-Wasm targets",
+ ctx.objErrStage1("wasmMemorySize is a compile error in non-Wasm targets",
\\export fn foo() void {
\\ _ = @wasmMemorySize(0);
\\ return;
@@ -8407,7 +8708,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:9: error: @wasmMemorySize is a wasm32 feature only",
});
- cases.add("wasmMemoryGrow is a compile error in non-Wasm targets",
+ ctx.objErrStage1("wasmMemoryGrow is a compile error in non-Wasm targets",
\\export fn foo() void {
\\ _ = @wasmMemoryGrow(0, 1);
\\ return;
@@ -8415,7 +8716,7 @@ 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",
+ ctx.objErrStage1("Issue #5586: Make unary minus for unsigned types a compile error",
\\export fn f1(x: u32) u32 {
\\ const y = -%x;
\\ return -y;
@@ -8430,7 +8731,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:8:12: error: negation of type 'u32'",
});
- cases.add("Issue #5618: coercion of ?*c_void to *c_void must fail.",
+ ctx.objErrStage1("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;
@@ -8440,15 +8741,16 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:4:9: error: expected type '*c_void', found '?*c_void'",
});
- cases.add("Issue #6823: don't allow .* to be followed by **",
+ ctx.objErrStage1("Issue #6823: don't allow .* to be followed by **",
\\fn foo() void {
\\ var sequence = "repeat".*** 10;
+ \\ _ = sequence;
\\}
, &[_][]const u8{
"tmp.zig:2:30: error: `.*` cannot be followed by `*`. Are you missing a space?",
});
- cases.add("Issue #9165: windows tcp server compilation error",
+ ctx.objErrStage1("Issue #9165: windows tcp server compilation error",
\\const std = @import("std");
\\pub const io_mode = .evented;
\\pub fn main() !void {
diff --git a/test/tests.zig b/test/tests.zig
index 8871c18428..0b736792b9 100644
--- a/test/tests.zig
+++ b/test/tests.zig
@@ -16,7 +16,6 @@ const LibExeObjStep = build.LibExeObjStep;
const compare_output = @import("compare_output.zig");
const standalone = @import("standalone.zig");
const stack_traces = @import("stack_traces.zig");
-const compile_errors = @import("compile_errors.zig");
const assemble_and_link = @import("assemble_and_link.zig");
const runtime_safety = @import("runtime_safety.zig");
const translate_c = @import("translate_c.zig");
@@ -384,21 +383,6 @@ pub fn addRuntimeSafetyTests(b: *build.Builder, test_filter: ?[]const u8, modes:
return cases.step;
}
-pub fn addCompileErrorTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step {
- const cases = b.allocator.create(CompileErrorContext) catch unreachable;
- cases.* = CompileErrorContext{
- .b = b,
- .step = b.step("test-compile-errors", "Run the compile error tests"),
- .test_index = 0,
- .test_filter = test_filter,
- .modes = modes,
- };
-
- compile_errors.addCases(cases);
-
- return cases.step;
-}
-
pub fn addStandaloneTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode, skip_non_native: bool, target: std.zig.CrossTarget) *build.Step {
const cases = b.allocator.create(StandaloneContext) catch unreachable;
cases.* = StandaloneContext{
@@ -840,304 +824,6 @@ pub const StackTracesContext = struct {
};
};
-pub const CompileErrorContext = struct {
- b: *build.Builder,
- step: *build.Step,
- test_index: usize,
- test_filter: ?[]const u8,
- modes: []const Mode,
-
- const TestCase = struct {
- name: []const u8,
- sources: ArrayList(SourceFile),
- expected_errors: ArrayList([]const u8),
- expect_exact: bool,
- link_libc: bool,
- is_exe: bool,
- is_test: bool,
- target: CrossTarget = CrossTarget{},
-
- const SourceFile = struct {
- filename: []const u8,
- source: []const u8,
- };
-
- pub fn addSourceFile(self: *TestCase, filename: []const u8, source: []const u8) void {
- self.sources.append(SourceFile{
- .filename = filename,
- .source = source,
- }) catch unreachable;
- }
-
- pub fn addExpectedError(self: *TestCase, text: []const u8) void {
- self.expected_errors.append(text) catch unreachable;
- }
- };
-
- const CompileCmpOutputStep = struct {
- pub const base_id = .custom;
-
- step: build.Step,
- context: *CompileErrorContext,
- name: []const u8,
- test_index: usize,
- case: *const TestCase,
- build_mode: Mode,
- write_src: *build.WriteFileStep,
-
- const ErrLineIter = struct {
- lines: mem.SplitIterator,
-
- const source_file = "tmp.zig";
-
- fn init(input: []const u8) ErrLineIter {
- return ErrLineIter{ .lines = mem.split(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,
- write_src: *build.WriteFileStep,
- ) *CompileCmpOutputStep {
- const allocator = context.b.allocator;
- const ptr = allocator.create(CompileCmpOutputStep) catch unreachable;
- ptr.* = CompileCmpOutputStep{
- .step = build.Step.init(.custom, "CompileCmpOutput", allocator, make),
- .context = context,
- .name = name,
- .test_index = context.test_index,
- .case = case,
- .build_mode = build_mode,
- .write_src = write_src,
- };
-
- context.test_index += 1;
- return ptr;
- }
-
- fn make(step: *build.Step) !void {
- const self = @fieldParentPtr(CompileCmpOutputStep, "step", step);
- const b = self.context.b;
-
- var zig_args = ArrayList([]const u8).init(b.allocator);
- zig_args.append(b.zig_exe) catch unreachable;
-
- if (self.case.is_exe) {
- try zig_args.append("build-exe");
- } else if (self.case.is_test) {
- try zig_args.append("test");
- } else {
- try zig_args.append("build-obj");
- }
- const root_src_basename = self.case.sources.items[0].filename;
- try zig_args.append(self.write_src.getFileSource(root_src_basename).?.getPath(b));
-
- zig_args.append("--name") catch unreachable;
- zig_args.append("test") catch unreachable;
-
- if (!self.case.target.isNative()) {
- try zig_args.append("-target");
- try zig_args.append(try self.case.target.zigTriple(b.allocator));
- }
-
- zig_args.append("-O") catch unreachable;
- zig_args.append(@tagName(self.build_mode)) catch unreachable;
-
- warn("Test {d}/{d} {s}...", .{ self.test_index + 1, self.context.test_index, self.name });
-
- if (b.verbose) {
- printInvocation(zig_args.items);
- }
-
- const child = std.ChildProcess.init(zig_args.items, b.allocator) catch unreachable;
- defer child.deinit();
-
- child.env_map = b.env_map;
- child.stdin_behavior = .Ignore;
- child.stdout_behavior = .Pipe;
- child.stderr_behavior = .Pipe;
-
- child.spawn() catch |err| debug.panic("Unable to spawn {s}: {s}\n", .{ zig_args.items[0], @errorName(err) });
-
- var stdout_buf = ArrayList(u8).init(b.allocator);
- var stderr_buf = ArrayList(u8).init(b.allocator);
-
- child.stdout.?.reader().readAllArrayList(&stdout_buf, max_stdout_size) catch unreachable;
- child.stderr.?.reader().readAllArrayList(&stderr_buf, max_stdout_size) catch unreachable;
-
- const term = child.wait() catch |err| {
- debug.panic("Unable to spawn {s}: {s}\n", .{ zig_args.items[0], @errorName(err) });
- };
- switch (term) {
- .Exited => |code| {
- if (code == 0) {
- printInvocation(zig_args.items);
- return error.CompilationIncorrectlySucceeded;
- }
- },
- else => {
- warn("Process {s} terminated unexpectedly\n", .{b.zig_exe});
- printInvocation(zig_args.items);
- return error.TestFailed;
- },
- }
-
- const stdout = stdout_buf.items;
- const stderr = stderr_buf.items;
-
- if (stdout.len != 0) {
- warn(
- \\
- \\Expected empty stdout, instead found:
- \\================================================
- \\{s}
- \\================================================
- \\
- , .{stdout});
- 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.items.len) break false;
- const expected = self.case.expected_errors.items[i];
- if (mem.indexOf(u8, line, expected) == null) break false;
- continue;
- } else true;
-
- ok = ok and i == self.case.expected_errors.items.len;
-
- if (!ok) {
- warn("\n======== Expected these compile errors: ========\n", .{});
- for (self.case.expected_errors.items) |expected| {
- warn("{s}\n", .{expected});
- }
- }
- } else {
- for (self.case.expected_errors.items) |expected| {
- if (mem.indexOf(u8, stderr, expected) == null) {
- warn(
- \\
- \\=========== Expected compile error: ============
- \\{s}
- \\
- , .{expected});
- ok = false;
- break;
- }
- }
- }
-
- if (!ok) {
- warn(
- \\================= Full output: =================
- \\{s}
- \\
- , .{stderr});
- return error.TestFailed;
- }
-
- warn("OK\n", .{});
- }
- };
-
- pub fn create(
- self: *CompileErrorContext,
- name: []const u8,
- source: []const u8,
- expected_lines: []const []const u8,
- ) *TestCase {
- const tc = self.b.allocator.create(TestCase) catch unreachable;
- tc.* = TestCase{
- .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,
- };
-
- tc.addSourceFile("tmp.zig", source);
- var arg_i: usize = 0;
- while (arg_i < expected_lines.len) : (arg_i += 1) {
- tc.addExpectedError(expected_lines[arg_i]);
- }
- return tc;
- }
-
- pub fn addC(self: *CompileErrorContext, name: []const u8, source: []const u8, expected_lines: []const []const u8) void {
- var tc = self.create(name, source, expected_lines);
- tc.link_libc = true;
- self.addCase(tc);
- }
-
- pub fn addExe(
- self: *CompileErrorContext,
- name: []const u8,
- source: []const u8,
- expected_lines: []const []const u8,
- ) void {
- var tc = self.create(name, source, expected_lines);
- tc.is_exe = true;
- self.addCase(tc);
- }
-
- pub fn add(
- self: *CompileErrorContext,
- name: []const u8,
- source: []const u8,
- expected_lines: []const []const u8,
- ) void {
- const tc = self.create(name, source, expected_lines);
- self.addCase(tc);
- }
-
- pub fn addTest(
- self: *CompileErrorContext,
- name: []const u8,
- source: []const u8,
- expected_lines: []const []const u8,
- ) void {
- const tc = self.create(name, source, expected_lines);
- tc.is_test = true;
- self.addCase(tc);
- }
-
- pub fn addCase(self: *CompileErrorContext, case: *const TestCase) void {
- const b = self.b;
-
- const annotated_case_name = fmt.allocPrint(self.b.allocator, "compile-error {s}", .{
- case.name,
- }) catch unreachable;
- if (self.test_filter) |filter| {
- if (mem.indexOf(u8, annotated_case_name, filter) == null) return;
- }
- const write_src = b.addWriteFiles();
- for (case.sources.items) |src_file| {
- write_src.add(src_file.filename, src_file.source);
- }
-
- const compile_and_cmp_errors = CompileCmpOutputStep.create(self, annotated_case_name, case, .Debug, write_src);
- compile_and_cmp_errors.step.dependOn(&write_src.step);
- self.step.dependOn(&compile_and_cmp_errors.step);
- }
-};
-
pub const StandaloneContext = struct {
b: *build.Builder,
step: *build.Step,
@@ -1312,13 +998,6 @@ pub const GenHContext = struct {
}
};
- fn printInvocation(args: []const []const u8) void {
- for (args) |arg| {
- warn("{s} ", .{arg});
- }
- warn("\n", .{});
- }
-
pub fn create(
self: *GenHContext,
filename: []const u8,
From 3f680abbe2c4d2eeefd0eb73b8af25d1768e6ceb Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Wed, 30 Jun 2021 18:03:54 -0700
Subject: [PATCH 07/15] stage2: tokenizer: require null terminated source
By requiring the source file to be null-terminated, we avoid extra
branching while simplifying the logic at the same time.
Running ast-check on a large zig source file (udivmodti4_test.zig),
master branch compared to this commit:
* 4% faster wall clock
* 7% fewer cache misses
* 1% fewer branches
---
lib/std/zig/ast.zig | 2 +-
lib/std/zig/parse.zig | 2 +-
lib/std/zig/parser_test.zig | 8 +-
lib/std/zig/tokenizer.zig | 221 ++++++++----------------------------
src/Compilation.zig | 2 +-
src/translate_c/ast.zig | 2 +-
6 files changed, 56 insertions(+), 181 deletions(-)
diff --git a/lib/std/zig/ast.zig b/lib/std/zig/ast.zig
index 512e4ec265..8eefe4fb22 100644
--- a/lib/std/zig/ast.zig
+++ b/lib/std/zig/ast.zig
@@ -20,7 +20,7 @@ pub const NodeList = std.MultiArrayList(Node);
pub const Tree = struct {
/// Reference to externally-owned data.
- source: []const u8,
+ source: [:0]const u8,
tokens: TokenList.Slice,
/// The root AST node is assumed to be index 0. Since there can be no
diff --git a/lib/std/zig/parse.zig b/lib/std/zig/parse.zig
index 5bafcce5b1..f7e782851f 100644
--- a/lib/std/zig/parse.zig
+++ b/lib/std/zig/parse.zig
@@ -17,7 +17,7 @@ pub const Error = error{ParseError} || Allocator.Error;
/// Result should be freed with tree.deinit() when there are
/// no more references to any of the tokens or nodes.
-pub fn parse(gpa: *Allocator, source: []const u8) Allocator.Error!Tree {
+pub fn parse(gpa: *Allocator, source: [:0]const u8) Allocator.Error!Tree {
var tokens = ast.TokenList{};
defer tokens.deinit(gpa);
diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig
index 907e06a1a6..26ef344f2c 100644
--- a/lib/std/zig/parser_test.zig
+++ b/lib/std/zig/parser_test.zig
@@ -5194,7 +5194,7 @@ const maxInt = std.math.maxInt;
var fixed_buffer_mem: [100 * 1024]u8 = undefined;
-fn testParse(source: []const u8, allocator: *mem.Allocator, anything_changed: *bool) ![]u8 {
+fn testParse(source: [:0]const u8, allocator: *mem.Allocator, anything_changed: *bool) ![]u8 {
const stderr = io.getStdErr().writer();
var tree = try std.zig.parse(allocator, source);
@@ -5222,7 +5222,7 @@ fn testParse(source: []const u8, allocator: *mem.Allocator, anything_changed: *b
anything_changed.* = !mem.eql(u8, formatted, source);
return formatted;
}
-fn testTransform(source: []const u8, expected_source: []const u8) !void {
+fn testTransform(source: [:0]const u8, expected_source: []const u8) !void {
const needed_alloc_count = x: {
// Try it once with unlimited memory, make sure it works
var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
@@ -5268,13 +5268,13 @@ fn testTransform(source: []const u8, expected_source: []const u8) !void {
}
}
}
-fn testCanonical(source: []const u8) !void {
+fn testCanonical(source: [:0]const u8) !void {
return testTransform(source, source);
}
const Error = std.zig.ast.Error.Tag;
-fn testError(source: []const u8, expected_errors: []const Error) !void {
+fn testError(source: [:0]const u8, expected_errors: []const Error) !void {
var tree = try std.zig.parse(std.testing.allocator, source);
defer tree.deinit(std.testing.allocator);
diff --git a/lib/std/zig/tokenizer.zig b/lib/std/zig/tokenizer.zig
index 94a20d958b..35926ac730 100644
--- a/lib/std/zig/tokenizer.zig
+++ b/lib/std/zig/tokenizer.zig
@@ -326,7 +326,7 @@ pub const Token = struct {
};
pub const Tokenizer = struct {
- buffer: []const u8,
+ buffer: [:0]const u8,
index: usize,
pending_invalid_token: ?Token,
@@ -335,7 +335,7 @@ pub const Tokenizer = struct {
std.debug.warn("{s} \"{s}\"\n", .{ @tagName(token.tag), self.buffer[token.start..token.end] });
}
- pub fn init(buffer: []const u8) Tokenizer {
+ pub fn init(buffer: [:0]const u8) Tokenizer {
// Skip the UTF-8 BOM if present
const src_start = if (mem.startsWith(u8, buffer, "\xEF\xBB\xBF")) 3 else @as(usize, 0);
return Tokenizer{
@@ -373,7 +373,6 @@ pub const Tokenizer = struct {
line_comment,
doc_comment_start,
doc_comment,
- container_doc_comment,
zero,
int_literal_dec,
int_literal_dec_no_underscore,
@@ -407,10 +406,6 @@ pub const Tokenizer = struct {
saw_at_sign,
};
- fn isIdentifierChar(char: u8) bool {
- return std.ascii.isAlNum(char) or char == '_';
- }
-
pub fn next(self: *Tokenizer) Token {
if (self.pending_invalid_token) |token| {
self.pending_invalid_token = null;
@@ -426,10 +421,11 @@ pub const Tokenizer = struct {
};
var seen_escape_digits: usize = undefined;
var remaining_code_units: usize = undefined;
- while (self.index < self.buffer.len) : (self.index += 1) {
+ while (true) : (self.index += 1) {
const c = self.buffer[self.index];
switch (state) {
.start => switch (c) {
+ 0 => break,
' ', '\n', '\t', '\r' => {
result.loc.start = self.index + 1;
},
@@ -705,18 +701,22 @@ pub const Tokenizer = struct {
self.index += 1;
break;
},
- '\n', '\r' => break, // Look for this error later.
+ 0, '\n', '\r' => break, // Look for this error later.
else => self.checkLiteralCharacter(),
},
.string_literal_backslash => switch (c) {
- '\n', '\r' => break, // Look for this error later.
+ 0, '\n', '\r' => break, // Look for this error later.
else => {
state = .string_literal;
},
},
.char_literal => switch (c) {
+ 0 => {
+ result.tag = .invalid;
+ break;
+ },
'\\' => {
state = .char_literal_backslash;
},
@@ -742,7 +742,7 @@ pub const Tokenizer = struct {
},
.char_literal_backslash => switch (c) {
- '\n' => {
+ 0, '\n' => {
result.tag = .invalid;
break;
},
@@ -834,6 +834,7 @@ pub const Tokenizer = struct {
},
.multiline_string_literal_line => switch (c) {
+ 0 => break,
'\n' => {
self.index += 1;
break;
@@ -1025,12 +1026,13 @@ pub const Tokenizer = struct {
},
},
.line_comment_start => switch (c) {
+ 0 => break,
'/' => {
state = .doc_comment_start;
},
'!' => {
result.tag = .container_doc_comment;
- state = .container_doc_comment;
+ state = .doc_comment;
},
'\n' => {
state = .start;
@@ -1046,7 +1048,7 @@ pub const Tokenizer = struct {
'/' => {
state = .line_comment;
},
- '\n' => {
+ 0, '\n' => {
result.tag = .doc_comment;
break;
},
@@ -1061,6 +1063,7 @@ pub const Tokenizer = struct {
},
},
.line_comment => switch (c) {
+ 0 => break,
'\n' => {
state = .start;
result.loc.start = self.index + 1;
@@ -1068,8 +1071,8 @@ pub const Tokenizer = struct {
'\t', '\r' => {},
else => self.checkLiteralCharacter(),
},
- .doc_comment, .container_doc_comment => switch (c) {
- '\n' => break,
+ .doc_comment => switch (c) {
+ 0, '\n' => break,
'\t', '\r' => {},
else => self.checkLiteralCharacter(),
},
@@ -1088,12 +1091,11 @@ pub const Tokenizer = struct {
self.index -= 1;
state = .int_literal_dec;
},
- else => {
- if (isIdentifierChar(c)) {
- result.tag = .invalid;
- }
+ 'a', 'c', 'd', 'f'...'n', 'p'...'w', 'y', 'z', 'A'...'D', 'F'...'Z' => {
+ result.tag = .invalid;
break;
},
+ else => break,
},
.int_literal_bin_no_underscore => switch (c) {
'0'...'1' => {
@@ -1109,12 +1111,11 @@ pub const Tokenizer = struct {
state = .int_literal_bin_no_underscore;
},
'0'...'1' => {},
- else => {
- if (isIdentifierChar(c)) {
- result.tag = .invalid;
- }
+ '2'...'9', 'a'...'z', 'A'...'Z' => {
+ result.tag = .invalid;
break;
},
+ else => break,
},
.int_literal_oct_no_underscore => switch (c) {
'0'...'7' => {
@@ -1130,12 +1131,11 @@ pub const Tokenizer = struct {
state = .int_literal_oct_no_underscore;
},
'0'...'7' => {},
- else => {
- if (isIdentifierChar(c)) {
- result.tag = .invalid;
- }
+ '8', '9', 'a'...'z', 'A'...'Z' => {
+ result.tag = .invalid;
break;
},
+ else => break,
},
.int_literal_dec_no_underscore => switch (c) {
'0'...'9' => {
@@ -1159,12 +1159,11 @@ pub const Tokenizer = struct {
result.tag = .float_literal;
},
'0'...'9' => {},
- else => {
- if (isIdentifierChar(c)) {
- result.tag = .invalid;
- }
+ 'a'...'d', 'f'...'z', 'A'...'D', 'F'...'Z' => {
+ result.tag = .invalid;
break;
},
+ else => break,
},
.int_literal_hex_no_underscore => switch (c) {
'0'...'9', 'a'...'f', 'A'...'F' => {
@@ -1188,12 +1187,11 @@ pub const Tokenizer = struct {
result.tag = .float_literal;
},
'0'...'9', 'a'...'f', 'A'...'F' => {},
- else => {
- if (isIdentifierChar(c)) {
- result.tag = .invalid;
- }
+ 'g'...'o', 'q'...'z', 'G'...'O', 'Q'...'Z' => {
+ result.tag = .invalid;
break;
},
+ else => break,
},
.num_dot_dec => switch (c) {
'.' => {
@@ -1206,12 +1204,11 @@ pub const Tokenizer = struct {
result.tag = .float_literal;
state = .float_fraction_dec;
},
- else => {
- if (isIdentifierChar(c)) {
- result.tag = .invalid;
- }
+ '_', 'a'...'z', 'A'...'Z' => {
+ result.tag = .invalid;
break;
},
+ else => break,
},
.num_dot_hex => switch (c) {
'.' => {
@@ -1224,12 +1221,11 @@ pub const Tokenizer = struct {
result.tag = .float_literal;
state = .float_fraction_hex;
},
- else => {
- if (isIdentifierChar(c)) {
- result.tag = .invalid;
- }
+ '_', 'g'...'z', 'G'...'Z' => {
+ result.tag = .invalid;
break;
},
+ else => break,
},
.float_fraction_dec_no_underscore => switch (c) {
'0'...'9' => {
@@ -1248,12 +1244,11 @@ pub const Tokenizer = struct {
state = .float_exponent_unsigned;
},
'0'...'9' => {},
- else => {
- if (isIdentifierChar(c)) {
- result.tag = .invalid;
- }
+ 'a'...'d', 'f'...'z', 'A'...'D', 'F'...'Z' => {
+ result.tag = .invalid;
break;
},
+ else => break,
},
.float_fraction_hex_no_underscore => switch (c) {
'0'...'9', 'a'...'f', 'A'...'F' => {
@@ -1272,12 +1267,11 @@ pub const Tokenizer = struct {
state = .float_exponent_unsigned;
},
'0'...'9', 'a'...'f', 'A'...'F' => {},
- else => {
- if (isIdentifierChar(c)) {
- result.tag = .invalid;
- }
+ 'g'...'o', 'q'...'z', 'G'...'O', 'Q'...'Z' => {
+ result.tag = .invalid;
break;
},
+ else => break,
},
.float_exponent_unsigned => switch (c) {
'+', '-' => {
@@ -1303,130 +1297,11 @@ pub const Tokenizer = struct {
state = .float_exponent_num_no_underscore;
},
'0'...'9' => {},
- else => {
- if (isIdentifierChar(c)) {
- result.tag = .invalid;
- }
+ 'a'...'z', 'A'...'Z' => {
+ result.tag = .invalid;
break;
},
- },
- }
- } else if (self.index == self.buffer.len) {
- switch (state) {
- .start,
- .int_literal_dec,
- .int_literal_bin,
- .int_literal_oct,
- .int_literal_hex,
- .num_dot_dec,
- .num_dot_hex,
- .float_fraction_dec,
- .float_fraction_hex,
- .float_exponent_num,
- .string_literal, // find this error later
- .multiline_string_literal_line,
- .builtin,
- .line_comment,
- .line_comment_start,
- => {},
-
- .identifier => {
- if (Token.getKeyword(self.buffer[result.loc.start..self.index])) |tag| {
- result.tag = tag;
- }
- },
- .doc_comment, .doc_comment_start => {
- result.tag = .doc_comment;
- },
- .container_doc_comment => {
- result.tag = .container_doc_comment;
- },
-
- .int_literal_dec_no_underscore,
- .int_literal_bin_no_underscore,
- .int_literal_oct_no_underscore,
- .int_literal_hex_no_underscore,
- .float_fraction_dec_no_underscore,
- .float_fraction_hex_no_underscore,
- .float_exponent_num_no_underscore,
- .float_exponent_unsigned,
- .saw_at_sign,
- .backslash,
- .char_literal,
- .char_literal_backslash,
- .char_literal_hex_escape,
- .char_literal_unicode_escape_saw_u,
- .char_literal_unicode_escape,
- .char_literal_unicode_invalid,
- .char_literal_end,
- .char_literal_unicode,
- .string_literal_backslash,
- => {
- result.tag = .invalid;
- },
-
- .equal => {
- result.tag = .equal;
- },
- .bang => {
- result.tag = .bang;
- },
- .minus => {
- result.tag = .minus;
- },
- .slash => {
- result.tag = .slash;
- },
- .zero => {
- result.tag = .integer_literal;
- },
- .ampersand => {
- result.tag = .ampersand;
- },
- .period => {
- result.tag = .period;
- },
- .period_2 => {
- result.tag = .ellipsis2;
- },
- .period_asterisk => {
- result.tag = .period_asterisk;
- },
- .pipe => {
- result.tag = .pipe;
- },
- .angle_bracket_angle_bracket_right => {
- result.tag = .angle_bracket_angle_bracket_right;
- },
- .angle_bracket_right => {
- result.tag = .angle_bracket_right;
- },
- .angle_bracket_angle_bracket_left => {
- result.tag = .angle_bracket_angle_bracket_left;
- },
- .angle_bracket_left => {
- result.tag = .angle_bracket_left;
- },
- .plus_percent => {
- result.tag = .plus_percent;
- },
- .plus => {
- result.tag = .plus;
- },
- .percent => {
- result.tag = .percent;
- },
- .caret => {
- result.tag = .caret;
- },
- .asterisk_percent => {
- result.tag = .asterisk_percent;
- },
- .asterisk => {
- result.tag = .asterisk;
- },
- .minus_percent => {
- result.tag = .minus_percent;
+ else => break,
},
}
}
diff --git a/src/Compilation.zig b/src/Compilation.zig
index c1cca84f62..68a008e0e1 100644
--- a/src/Compilation.zig
+++ b/src/Compilation.zig
@@ -1541,7 +1541,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
}
}
- if (comp.bin_file.options.use_stage1) {
+ if (comp.bin_file.options.use_stage1 and comp.bin_file.options.module != null) {
try comp.work_queue.writeItem(.{ .stage1_module = {} });
}
diff --git a/src/translate_c/ast.zig b/src/translate_c/ast.zig
index 70c8c6559f..cdf8d778b2 100644
--- a/src/translate_c/ast.zig
+++ b/src/translate_c/ast.zig
@@ -754,7 +754,7 @@ pub fn render(gpa: *Allocator, nodes: []const Node) !std.zig.ast.Tree {
});
return std.zig.ast.Tree{
- .source = ctx.buf.toOwnedSlice(),
+ .source = try ctx.buf.toOwnedSliceSentinel(0),
.tokens = ctx.tokens.toOwnedSlice(),
.nodes = ctx.nodes.toOwnedSlice(),
.extra_data = ctx.extra_data.toOwnedSlice(gpa),
From 24c432608f6b07020fa0b18fc9c868ad6abd9b15 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Thu, 1 Jul 2021 00:14:58 -0700
Subject: [PATCH 08/15] stage2: improve compile errors from tokenizer
In order to not regress the quality of compile errors, some improvements
had to be made.
* std.zig.parseCharLiteral is improved to return more detailed parse
failure information.
* tokenizer is improved to handle null bytes in the middle of strings,
character literals, and line comments.
* validating how many unicode escape digits in string literals is moved
to std.zig.parseStringLiteral rather than handled in the tokenizer.
* when a tokenizer error occurs, if the reported token is the 'invalid'
tag, an error note is added to point to the invalid byte location.
Further improvements would be:
- Mention the expected set of allowed bytes at this location.
- Display the invalid byte (if printable, print it, otherwise
escape-print it).
---
lib/std/zig.zig | 203 +++++++++++++++++++++++++++-----------
lib/std/zig/tokenizer.zig | 43 ++++----
src/AstGen.zig | 74 ++++++++++++--
src/Module.zig | 9 ++
src/main.zig | 20 ++++
test/compile_errors.zig | 60 +++++++----
6 files changed, 306 insertions(+), 103 deletions(-)
diff --git a/lib/std/zig.zig b/lib/std/zig.zig
index 034cf34d9b..4adbbe0b6a 100644
--- a/lib/std/zig.zig
+++ b/lib/std/zig.zig
@@ -6,6 +6,7 @@
const std = @import("std.zig");
const tokenizer = @import("zig/tokenizer.zig");
const fmt = @import("zig/fmt.zig");
+const assert = std.debug.assert;
pub const Token = tokenizer.Token;
pub const Tokenizer = tokenizer.Tokenizer;
@@ -183,29 +184,48 @@ pub fn binNameAlloc(allocator: *std.mem.Allocator, options: BinNameOptions) erro
}
}
+pub const ParsedCharLiteral = union(enum) {
+ success: u32,
+ /// The character after backslash is not recognized.
+ invalid_escape_character: usize,
+ /// Expected hex digit at this index.
+ expected_hex_digit: usize,
+ /// Unicode escape sequence had no digits with rbrace at this index.
+ empty_unicode_escape_sequence: usize,
+ /// Expected hex digit or '}' at this index.
+ expected_hex_digit_or_rbrace: usize,
+ /// The unicode point is outside the range of Unicode codepoints.
+ unicode_escape_overflow: usize,
+ /// Expected '{' at this index.
+ expected_lbrace: usize,
+ /// Expected the terminating single quote at this index.
+ expected_end: usize,
+ /// The character at this index cannot be represented without an escape sequence.
+ invalid_character: usize,
+};
+
/// Only validates escape sequence characters.
/// Slice must be valid utf8 starting and ending with "'" and exactly one codepoint in between.
-pub fn parseCharLiteral(
- slice: []const u8,
- bad_index: *usize, // populated if error.InvalidCharacter is returned
-) error{InvalidCharacter}!u32 {
- std.debug.assert(slice.len >= 3 and slice[0] == '\'' and slice[slice.len - 1] == '\'');
+pub fn parseCharLiteral(slice: []const u8) ParsedCharLiteral {
+ assert(slice.len >= 3 and slice[0] == '\'' and slice[slice.len - 1] == '\'');
- if (slice[1] == '\\') {
- switch (slice[2]) {
- 'n' => return '\n',
- 'r' => return '\r',
- '\\' => return '\\',
- 't' => return '\t',
- '\'' => return '\'',
- '"' => return '"',
+ switch (slice[1]) {
+ 0 => return .{ .invalid_character = 1 },
+ '\\' => switch (slice[2]) {
+ 'n' => return .{ .success = '\n' },
+ 'r' => return .{ .success = '\r' },
+ '\\' => return .{ .success = '\\' },
+ 't' => return .{ .success = '\t' },
+ '\'' => return .{ .success = '\'' },
+ '"' => return .{ .success = '"' },
'x' => {
- if (slice.len != 6) {
- bad_index.* = slice.len - 2;
- return error.InvalidCharacter;
+ if (slice.len < 4) {
+ return .{ .expected_hex_digit = 3 };
}
var value: u32 = 0;
- for (slice[3..5]) |c, i| {
+ var i: usize = 3;
+ while (i < 5) : (i += 1) {
+ const c = slice[i];
switch (c) {
'0'...'9' => {
value *= 16;
@@ -220,20 +240,28 @@ pub fn parseCharLiteral(
value += c - 'A' + 10;
},
else => {
- bad_index.* = 3 + i;
- return error.InvalidCharacter;
+ return .{ .expected_hex_digit = i };
},
}
}
- return value;
+ if (slice[i] != '\'') {
+ return .{ .expected_end = i };
+ }
+ return .{ .success = value };
},
'u' => {
- if (slice.len < "'\\u{0}'".len or slice[3] != '{' or slice[slice.len - 2] != '}') {
- bad_index.* = 2;
- return error.InvalidCharacter;
+ var i: usize = 3;
+ if (slice[i] != '{') {
+ return .{ .expected_lbrace = i };
}
+ i += 1;
+ if (slice[i] == '}') {
+ return .{ .empty_unicode_escape_sequence = i };
+ }
+
var value: u32 = 0;
- for (slice[4 .. slice.len - 2]) |c, i| {
+ while (i < slice.len) : (i += 1) {
+ const c = slice[i];
switch (c) {
'0'...'9' => {
value *= 16;
@@ -247,49 +275,112 @@ pub fn parseCharLiteral(
value *= 16;
value += c - 'A' + 10;
},
- else => {
- bad_index.* = 4 + i;
- return error.InvalidCharacter;
+ '}' => {
+ i += 1;
+ break;
},
+ else => return .{ .expected_hex_digit_or_rbrace = i },
}
if (value > 0x10ffff) {
- bad_index.* = 4 + i;
- return error.InvalidCharacter;
+ return .{ .unicode_escape_overflow = i };
}
}
- return value;
+ if (slice[i] != '\'') {
+ return .{ .expected_end = i };
+ }
+ return .{ .success = value };
},
- else => {
- bad_index.* = 2;
- return error.InvalidCharacter;
- },
- }
+ else => return .{ .invalid_escape_character = 2 },
+ },
+ else => {
+ const codepoint = std.unicode.utf8Decode(slice[1 .. slice.len - 1]) catch unreachable;
+ return .{ .success = codepoint };
+ },
}
- return std.unicode.utf8Decode(slice[1 .. slice.len - 1]) catch unreachable;
}
test "parseCharLiteral" {
- var bad_index: usize = undefined;
- try std.testing.expectEqual(try parseCharLiteral("'a'", &bad_index), 'a');
- try std.testing.expectEqual(try parseCharLiteral("'ä'", &bad_index), 'ä');
- try std.testing.expectEqual(try parseCharLiteral("'\\x00'", &bad_index), 0);
- try std.testing.expectEqual(try parseCharLiteral("'\\x4f'", &bad_index), 0x4f);
- try std.testing.expectEqual(try parseCharLiteral("'\\x4F'", &bad_index), 0x4f);
- try std.testing.expectEqual(try parseCharLiteral("'ぁ'", &bad_index), 0x3041);
- try std.testing.expectEqual(try parseCharLiteral("'\\u{0}'", &bad_index), 0);
- try std.testing.expectEqual(try parseCharLiteral("'\\u{3041}'", &bad_index), 0x3041);
- try std.testing.expectEqual(try parseCharLiteral("'\\u{7f}'", &bad_index), 0x7f);
- try std.testing.expectEqual(try parseCharLiteral("'\\u{7FFF}'", &bad_index), 0x7FFF);
+ try std.testing.expectEqual(
+ ParsedCharLiteral{ .success = 'a' },
+ parseCharLiteral("'a'"),
+ );
+ try std.testing.expectEqual(
+ ParsedCharLiteral{ .success = 'ä' },
+ parseCharLiteral("'ä'"),
+ );
+ try std.testing.expectEqual(
+ ParsedCharLiteral{ .success = 0 },
+ parseCharLiteral("'\\x00'"),
+ );
+ try std.testing.expectEqual(
+ ParsedCharLiteral{ .success = 0x4f },
+ parseCharLiteral("'\\x4f'"),
+ );
+ try std.testing.expectEqual(
+ ParsedCharLiteral{ .success = 0x4f },
+ parseCharLiteral("'\\x4F'"),
+ );
+ try std.testing.expectEqual(
+ ParsedCharLiteral{ .success = 0x3041 },
+ parseCharLiteral("'ぁ'"),
+ );
+ try std.testing.expectEqual(
+ ParsedCharLiteral{ .success = 0 },
+ parseCharLiteral("'\\u{0}'"),
+ );
+ try std.testing.expectEqual(
+ ParsedCharLiteral{ .success = 0x3041 },
+ parseCharLiteral("'\\u{3041}'"),
+ );
+ try std.testing.expectEqual(
+ ParsedCharLiteral{ .success = 0x7f },
+ parseCharLiteral("'\\u{7f}'"),
+ );
+ try std.testing.expectEqual(
+ ParsedCharLiteral{ .success = 0x7fff },
+ parseCharLiteral("'\\u{7FFF}'"),
+ );
- try std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\x0'", &bad_index));
- try std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\x000'", &bad_index));
- try std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\y'", &bad_index));
- try std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\u'", &bad_index));
- try std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\uFFFF'", &bad_index));
- try std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\u{}'", &bad_index));
- try std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\u{FFFFFF}'", &bad_index));
- try std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\u{FFFF'", &bad_index));
- try std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\u{FFFF}x'", &bad_index));
+ try std.testing.expectEqual(
+ ParsedCharLiteral{ .expected_hex_digit = 4 },
+ parseCharLiteral("'\\x0'"),
+ );
+ try std.testing.expectEqual(
+ ParsedCharLiteral{ .expected_end = 5 },
+ parseCharLiteral("'\\x000'"),
+ );
+ try std.testing.expectEqual(
+ ParsedCharLiteral{ .invalid_escape_character = 2 },
+ parseCharLiteral("'\\y'"),
+ );
+ try std.testing.expectEqual(
+ ParsedCharLiteral{ .expected_lbrace = 3 },
+ parseCharLiteral("'\\u'"),
+ );
+ try std.testing.expectEqual(
+ ParsedCharLiteral{ .expected_lbrace = 3 },
+ parseCharLiteral("'\\uFFFF'"),
+ );
+ try std.testing.expectEqual(
+ ParsedCharLiteral{ .empty_unicode_escape_sequence = 4 },
+ parseCharLiteral("'\\u{}'"),
+ );
+ try std.testing.expectEqual(
+ ParsedCharLiteral{ .unicode_escape_overflow = 9 },
+ parseCharLiteral("'\\u{FFFFFF}'"),
+ );
+ try std.testing.expectEqual(
+ ParsedCharLiteral{ .expected_hex_digit_or_rbrace = 8 },
+ parseCharLiteral("'\\u{FFFF'"),
+ );
+ try std.testing.expectEqual(
+ ParsedCharLiteral{ .expected_end = 9 },
+ parseCharLiteral("'\\u{FFFF}x'"),
+ );
+ try std.testing.expectEqual(
+ ParsedCharLiteral{ .invalid_character = 1 },
+ parseCharLiteral("'\x00'"),
+ );
}
test {
diff --git a/lib/std/zig/tokenizer.zig b/lib/std/zig/tokenizer.zig
index 35926ac730..1025af5a71 100644
--- a/lib/std/zig/tokenizer.zig
+++ b/lib/std/zig/tokenizer.zig
@@ -701,12 +701,19 @@ pub const Tokenizer = struct {
self.index += 1;
break;
},
- 0, '\n', '\r' => break, // Look for this error later.
+ 0 => {
+ if (self.index == self.buffer.len) {
+ break;
+ } else {
+ self.checkLiteralCharacter();
+ }
+ },
+ '\n', '\r' => break, // Look for this error later.
else => self.checkLiteralCharacter(),
},
.string_literal_backslash => switch (c) {
- 0, '\n', '\r' => break, // Look for this error later.
+ '\n', '\r' => break, // Look for this error later.
else => {
state = .string_literal;
},
@@ -774,7 +781,6 @@ pub const Tokenizer = struct {
.char_literal_unicode_escape_saw_u => switch (c) {
'{' => {
state = .char_literal_unicode_escape;
- seen_escape_digits = 0;
},
else => {
result.tag = .invalid;
@@ -783,16 +789,9 @@ pub const Tokenizer = struct {
},
.char_literal_unicode_escape => switch (c) {
- '0'...'9', 'a'...'f', 'A'...'F' => {
- seen_escape_digits += 1;
- },
+ '0'...'9', 'a'...'f', 'A'...'F' => {},
'}' => {
- if (seen_escape_digits == 0) {
- result.tag = .invalid;
- state = .char_literal_unicode_invalid;
- } else {
- state = .char_literal_end;
- }
+ state = .char_literal_end; // too many/few digits handled later
},
else => {
result.tag = .invalid;
@@ -1026,7 +1025,13 @@ pub const Tokenizer = struct {
},
},
.line_comment_start => switch (c) {
- 0 => break,
+ 0 => {
+ if (self.index != self.buffer.len) {
+ result.tag = .invalid;
+ self.index += 1;
+ }
+ break;
+ },
'/' => {
state = .doc_comment_start;
},
@@ -1441,7 +1446,7 @@ test "tokenizer - code point literal with unicode escapes" {
, &.{ .invalid, .invalid });
try testTokenize(
\\'\u{}'
- , &.{ .invalid, .invalid });
+ , &.{.char_literal});
try testTokenize(
\\'\u{s}'
, &.{ .invalid, .invalid });
@@ -1924,15 +1929,17 @@ test "tokenizer - invalid builtin identifiers" {
try testTokenize("@0()", &.{ .invalid, .integer_literal, .l_paren, .r_paren });
}
-fn testTokenize(source: []const u8, expected_tokens: []const Token.Tag) !void {
+fn testTokenize(source: [:0]const u8, expected_tokens: []const Token.Tag) !void {
var tokenizer = Tokenizer.init(source);
for (expected_tokens) |expected_token_id| {
const token = tokenizer.next();
if (token.tag != expected_token_id) {
- std.debug.panic("expected {s}, found {s}\n", .{ @tagName(expected_token_id), @tagName(token.tag) });
+ std.debug.panic("expected {s}, found {s}\n", .{
+ @tagName(expected_token_id), @tagName(token.tag),
+ });
}
}
const last_token = tokenizer.next();
- try std.testing.expect(last_token.tag == .eof);
- try std.testing.expect(last_token.loc.start == source.len);
+ try std.testing.expectEqual(Token.Tag.eof, last_token.tag);
+ try std.testing.expectEqual(source.len, last_token.loc.start);
}
diff --git a/src/AstGen.zig b/src/AstGen.zig
index 64f5f012f0..5b9851b0ae 100644
--- a/src/AstGen.zig
+++ b/src/AstGen.zig
@@ -6380,20 +6380,76 @@ fn charLiteral(gz: *GenZir, rl: ResultLoc, node: ast.Node.Index) !Zir.Inst.Ref {
const main_token = main_tokens[node];
const slice = tree.tokenSlice(main_token);
- var bad_index: usize = undefined;
- const value = std.zig.parseCharLiteral(slice, &bad_index) catch |err| switch (err) {
- error.InvalidCharacter => {
- const bad_byte = slice[bad_index];
+ switch (std.zig.parseCharLiteral(slice)) {
+ .success => |codepoint| {
+ const result = try gz.addInt(codepoint);
+ return rvalue(gz, rl, result, node);
+ },
+ .invalid_escape_character => |bad_index| {
return astgen.failOff(
main_token,
@intCast(u32, bad_index),
- "invalid character: '{c}'\n",
- .{bad_byte},
+ "invalid escape character: '{c}'",
+ .{slice[bad_index]},
);
},
- };
- const result = try gz.addInt(value);
- return rvalue(gz, rl, result, node);
+ .expected_hex_digit => |bad_index| {
+ return astgen.failOff(
+ main_token,
+ @intCast(u32, bad_index),
+ "expected hex digit, found '{c}'",
+ .{slice[bad_index]},
+ );
+ },
+ .empty_unicode_escape_sequence => |bad_index| {
+ return astgen.failOff(
+ main_token,
+ @intCast(u32, bad_index),
+ "empty unicode escape sequence",
+ .{},
+ );
+ },
+ .expected_hex_digit_or_rbrace => |bad_index| {
+ return astgen.failOff(
+ main_token,
+ @intCast(u32, bad_index),
+ "expected hex digit or '}}', found '{c}'",
+ .{slice[bad_index]},
+ );
+ },
+ .unicode_escape_overflow => |bad_index| {
+ return astgen.failOff(
+ main_token,
+ @intCast(u32, bad_index),
+ "unicode escape too large to be a valid codepoint",
+ .{},
+ );
+ },
+ .expected_lbrace => |bad_index| {
+ return astgen.failOff(
+ main_token,
+ @intCast(u32, bad_index),
+ "expected '{{', found '{c}",
+ .{slice[bad_index]},
+ );
+ },
+ .expected_end => |bad_index| {
+ return astgen.failOff(
+ main_token,
+ @intCast(u32, bad_index),
+ "expected ending single quote ('), found '{c}",
+ .{slice[bad_index]},
+ );
+ },
+ .invalid_character => |bad_index| {
+ return astgen.failOff(
+ main_token,
+ @intCast(u32, bad_index),
+ "invalid byte in character literal: '{c}'",
+ .{slice[bad_index]},
+ );
+ },
+ }
}
fn integerLiteral(gz: *GenZir, rl: ResultLoc, node: ast.Node.Index) InnerError!Zir.Inst.Ref {
diff --git a/src/Module.zig b/src/Module.zig
index d37452d99d..2e421ea65b 100644
--- a/src/Module.zig
+++ b/src/Module.zig
@@ -2466,6 +2466,7 @@ pub fn astGenFile(mod: *Module, file: *Scope.File) !void {
defer msg.deinit();
const token_starts = file.tree.tokens.items(.start);
+ const token_tags = file.tree.tokens.items(.tag);
try file.tree.renderError(parse_err, msg.writer());
const err_msg = try gpa.create(ErrorMsg);
@@ -2477,6 +2478,14 @@ pub fn astGenFile(mod: *Module, file: *Scope.File) !void {
},
.msg = msg.toOwnedSlice(),
};
+ if (token_tags[parse_err.token] == .invalid) {
+ const bad_off = @intCast(u32, file.tree.tokenSlice(parse_err.token).len);
+ try mod.errNoteNonLazy(.{
+ .file_scope = file,
+ .parent_decl_node = 0,
+ .lazy = .{ .byte_abs = token_starts[parse_err.token] + bad_off },
+ }, err_msg, "invalid byte here", .{});
+ }
{
const lock = comp.mutex.acquire();
diff --git a/src/main.zig b/src/main.zig
index 760ad79a3a..f4ca11a96a 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -3380,6 +3380,7 @@ fn printErrMsgToStdErr(
color: Color,
) !void {
const lok_token = parse_error.token;
+ const token_tags = tree.tokens.items(.tag);
const start_loc = tree.tokenLocation(0, lok_token);
const source_line = tree.source[start_loc.line_start..start_loc.line_end];
@@ -3389,6 +3390,24 @@ fn printErrMsgToStdErr(
try tree.renderError(parse_error, writer);
const text = text_buf.items;
+ var notes_buffer: [1]Compilation.AllErrors.Message = undefined;
+ var notes_len: usize = 0;
+
+ if (token_tags[parse_error.token] == .invalid) {
+ const bad_off = @intCast(u32, tree.tokenSlice(parse_error.token).len);
+ notes_buffer[notes_len] = .{
+ .src = .{
+ .src_path = path,
+ .msg = "invalid byte here",
+ .byte_offset = @intCast(u32, start_loc.line_start) + bad_off,
+ .line = @intCast(u32, start_loc.line),
+ .column = @intCast(u32, start_loc.column) + bad_off,
+ .source_line = source_line,
+ },
+ };
+ notes_len += 1;
+ }
+
const message: Compilation.AllErrors.Message = .{
.src = .{
.src_path = path,
@@ -3397,6 +3416,7 @@ fn printErrMsgToStdErr(
.line = @intCast(u32, start_loc.line),
.column = @intCast(u32, start_loc.column),
.source_line = source_line,
+ .notes = notes_buffer[0..notes_len],
},
};
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
index 3006a6889d..232dd942cc 100644
--- a/test/compile_errors.zig
+++ b/test/compile_errors.zig
@@ -1506,7 +1506,8 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = bad;
\\}
, &[_][]const u8{
- "tmp.zig:2:28: error: invalid character: 'a'",
+ "tmp.zig:2:21: error: expected expression, found 'invalid'",
+ "tmp.zig:2:28: note: invalid byte here",
});
ctx.objErrStage1("invalid exponent in float literal - 2",
@@ -1515,7 +1516,8 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = bad;
\\}
, &[_][]const u8{
- "tmp.zig:2:29: error: invalid character: 'F'",
+ "tmp.zig:2:21: error: expected expression, found 'invalid'",
+ "tmp.zig:2:29: note: invalid byte here",
});
ctx.objErrStage1("invalid underscore placement in float literal - 1",
@@ -1524,7 +1526,8 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = bad;
\\}
, &[_][]const u8{
- "tmp.zig:2:23: error: invalid character: '_'",
+ "tmp.zig:2:21: error: expected expression, found 'invalid'",
+ "tmp.zig:2:23: note: invalid byte here",
});
ctx.objErrStage1("invalid underscore placement in float literal - 2",
@@ -1533,7 +1536,8 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = bad;
\\}
, &[_][]const u8{
- "tmp.zig:2:23: error: invalid character: '.'",
+ "tmp.zig:2:21: error: expected expression, found 'invalid'",
+ "tmp.zig:2:23: note: invalid byte here",
});
ctx.objErrStage1("invalid underscore placement in float literal - 3",
@@ -1542,7 +1546,8 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = bad;
\\}
, &[_][]const u8{
- "tmp.zig:2:25: error: invalid character: ';'",
+ "tmp.zig:2:21: error: expected expression, found 'invalid'",
+ "tmp.zig:2:25: note: invalid byte here",
});
ctx.objErrStage1("invalid underscore placement in float literal - 4",
@@ -1551,7 +1556,8 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = bad;
\\}
, &[_][]const u8{
- "tmp.zig:2:25: error: invalid character: '_'",
+ "tmp.zig:2:21: error: expected expression, found 'invalid'",
+ "tmp.zig:2:25: note: invalid byte here",
});
ctx.objErrStage1("invalid underscore placement in float literal - 5",
@@ -1560,7 +1566,8 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = bad;
\\}
, &[_][]const u8{
- "tmp.zig:2:26: error: invalid character: '_'",
+ "tmp.zig:2:21: error: expected expression, found 'invalid'",
+ "tmp.zig:2:26: note: invalid byte here",
});
ctx.objErrStage1("invalid underscore placement in float literal - 6",
@@ -1569,7 +1576,8 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = bad;
\\}
, &[_][]const u8{
- "tmp.zig:2:26: error: invalid character: '_'",
+ "tmp.zig:2:21: error: expected expression, found 'invalid'",
+ "tmp.zig:2:26: note: invalid byte here",
});
ctx.objErrStage1("invalid underscore placement in float literal - 7",
@@ -1578,7 +1586,8 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = bad;
\\}
, &[_][]const u8{
- "tmp.zig:2:28: error: invalid character: ';'",
+ "tmp.zig:2:21: error: expected expression, found 'invalid'",
+ "tmp.zig:2:28: note: invalid byte here",
});
ctx.objErrStage1("invalid underscore placement in float literal - 9",
@@ -1587,7 +1596,8 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = bad;
\\}
, &[_][]const u8{
- "tmp.zig:2:23: error: invalid character: '_'",
+ "tmp.zig:2:21: error: expected expression, found 'invalid'",
+ "tmp.zig:2:23: note: invalid byte here",
});
ctx.objErrStage1("invalid underscore placement in float literal - 10",
@@ -1596,7 +1606,8 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = bad;
\\}
, &[_][]const u8{
- "tmp.zig:2:25: error: invalid character: '_'",
+ "tmp.zig:2:21: error: expected expression, found 'invalid'",
+ "tmp.zig:2:25: note: invalid byte here",
});
ctx.objErrStage1("invalid underscore placement in float literal - 11",
@@ -1605,7 +1616,8 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = bad;
\\}
, &[_][]const u8{
- "tmp.zig:2:28: error: invalid character: '_'",
+ "tmp.zig:2:21: error: expected expression, found 'invalid'",
+ "tmp.zig:2:28: note: invalid byte here",
});
ctx.objErrStage1("invalid underscore placement in float literal - 12",
@@ -1614,7 +1626,8 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = bad;
\\}
, &[_][]const u8{
- "tmp.zig:2:23: error: invalid character: 'x'",
+ "tmp.zig:2:21: error: expected expression, found 'invalid'",
+ "tmp.zig:2:23: note: invalid byte here",
});
ctx.objErrStage1("invalid underscore placement in float literal - 13",
@@ -1623,7 +1636,8 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = bad;
\\}
, &[_][]const u8{
- "tmp.zig:2:23: error: invalid character: '_'",
+ "tmp.zig:2:21: error: expected expression, found 'invalid'",
+ "tmp.zig:2:23: note: invalid byte here",
});
ctx.objErrStage1("invalid underscore placement in float literal - 14",
@@ -1632,7 +1646,8 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = bad;
\\}
, &[_][]const u8{
- "tmp.zig:2:27: error: invalid character: 'p'",
+ "tmp.zig:2:21: error: expected expression, found 'invalid'",
+ "tmp.zig:2:27: note: invalid byte here",
});
ctx.objErrStage1("invalid underscore placement in int literal - 1",
@@ -1641,7 +1656,8 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = bad;
\\}
, &[_][]const u8{
- "tmp.zig:2:26: error: invalid character: ';'",
+ "tmp.zig:2:21: error: expected expression, found 'invalid'",
+ "tmp.zig:2:26: note: invalid byte here",
});
ctx.objErrStage1("invalid underscore placement in int literal - 2",
@@ -1650,7 +1666,8 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = bad;
\\}
, &[_][]const u8{
- "tmp.zig:2:28: error: invalid character: ';'",
+ "tmp.zig:2:21: error: expected expression, found 'invalid'",
+ "tmp.zig:2:28: note: invalid byte here",
});
ctx.objErrStage1("invalid underscore placement in int literal - 3",
@@ -1659,7 +1676,8 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = bad;
\\}
, &[_][]const u8{
- "tmp.zig:2:28: error: invalid character: ';'",
+ "tmp.zig:2:21: error: expected expression, found 'invalid'",
+ "tmp.zig:2:28: note: invalid byte here",
});
ctx.objErrStage1("invalid underscore placement in int literal - 4",
@@ -1668,7 +1686,8 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = bad;
\\}
, &[_][]const u8{
- "tmp.zig:2:28: error: invalid character: ';'",
+ "tmp.zig:2:21: error: expected expression, found 'invalid'",
+ "tmp.zig:2:28: note: invalid byte here",
});
ctx.objErrStage1("comptime struct field, no init value",
@@ -7544,7 +7563,8 @@ pub fn addCases(ctx: *TestContext) !void {
\\ const a = '\U1234';
\\}
, &[_][]const u8{
- "tmp.zig:2:17: error: invalid character: 'U'",
+ "tmp.zig:2:15: error: expected expression, found 'invalid'",
+ "tmp.zig:2:18: note: invalid byte here",
});
ctx.objErrStage1("invalid empty unicode escape",
From abfee127353cbdadab4282b61056222cdfbec2d4 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Thu, 1 Jul 2021 15:42:21 -0700
Subject: [PATCH 09/15] AstGen: pass more compile error tests
* Implement "initializing array with struct syntax"
* Implement "'_' used as an identifier without @\"_\" syntax"
* Fix source location of "missing parameter name"
* Update test cases where appropriate
---
src/AstGen.zig | 55 +++++++++++++++++++++++++++--------------
test/compile_errors.zig | 21 ++++++++++------
2 files changed, 50 insertions(+), 26 deletions(-)
diff --git a/src/AstGen.zig b/src/AstGen.zig
index 5b9851b0ae..1e9abda660 100644
--- a/src/AstGen.zig
+++ b/src/AstGen.zig
@@ -1313,22 +1313,23 @@ fn structInitExpr(
const astgen = gz.astgen;
const tree = astgen.tree;
- if (struct_init.ast.fields.len == 0) {
- if (struct_init.ast.type_expr == 0) {
+ if (struct_init.ast.type_expr == 0) {
+ if (struct_init.ast.fields.len == 0) {
return rvalue(gz, rl, .empty_struct, node);
}
- array: {
- const node_tags = tree.nodes.items(.tag);
- const main_tokens = tree.nodes.items(.main_token);
- const array_type: ast.full.ArrayType = switch (node_tags[struct_init.ast.type_expr]) {
- .array_type => tree.arrayType(struct_init.ast.type_expr),
- .array_type_sentinel => tree.arrayTypeSentinel(struct_init.ast.type_expr),
- else => break :array,
- };
+ } else array: {
+ const node_tags = tree.nodes.items(.tag);
+ const main_tokens = tree.nodes.items(.main_token);
+ const array_type: ast.full.ArrayType = switch (node_tags[struct_init.ast.type_expr]) {
+ .array_type => tree.arrayType(struct_init.ast.type_expr),
+ .array_type_sentinel => tree.arrayTypeSentinel(struct_init.ast.type_expr),
+ else => break :array,
+ };
+ const is_inferred_array_len = node_tags[array_type.ast.elem_count] == .identifier and
// This intentionally does not support `@"_"` syntax.
- if (node_tags[array_type.ast.elem_count] == .identifier and
- mem.eql(u8, tree.tokenSlice(main_tokens[array_type.ast.elem_count]), "_"))
- {
+ mem.eql(u8, tree.tokenSlice(main_tokens[array_type.ast.elem_count]), "_");
+ if (struct_init.ast.fields.len == 0) {
+ if (is_inferred_array_len) {
const elem_type = try typeExpr(gz, scope, array_type.ast.elem_type);
const array_type_inst = if (array_type.ast.sentinel == 0) blk: {
break :blk try gz.addBin(.array_type, .zero_usize, elem_type);
@@ -1339,11 +1340,18 @@ fn structInitExpr(
const result = try gz.addUnNode(.struct_init_empty, array_type_inst, node);
return rvalue(gz, rl, result, node);
}
+ const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
+ const result = try gz.addUnNode(.struct_init_empty, ty_inst, node);
+ return rvalue(gz, rl, result, node);
+ } else {
+ return astgen.failNode(
+ struct_init.ast.type_expr,
+ "initializing array with struct syntax",
+ .{},
+ );
}
- const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
- const result = try gz.addUnNode(.struct_init_empty, ty_inst, node);
- return rvalue(gz, rl, result, node);
}
+
switch (rl) {
.discard => {
if (struct_init.ast.type_expr != 0)
@@ -2266,6 +2274,10 @@ fn varDecl(
const token_tags = tree.tokens.items(.tag);
const name_token = var_decl.ast.mut_token + 1;
+ const ident_name_raw = tree.tokenSlice(name_token);
+ if (mem.eql(u8, ident_name_raw, "_")) {
+ return astgen.failTok(name_token, "'_' used as an identifier without @\"_\" syntax", .{});
+ }
const ident_name = try astgen.identAsString(name_token);
// Local variables shadowing detection, including function parameters.
@@ -3003,7 +3015,11 @@ fn fnDecl(
var it = fn_proto.iterate(tree.*);
while (it.next()) |param| : (i += 1) {
const name_token = param.name_token orelse {
- return astgen.failNode(param.type_expr, "missing parameter name", .{});
+ if (param.anytype_ellipsis3) |tok| {
+ return astgen.failTok(tok, "missing parameter name", .{});
+ } else {
+ return astgen.failNode(param.type_expr, "missing parameter name", .{});
+ }
};
if (param.type_expr != 0)
_ = try typeExpr(&fn_gz, params_scope, param.type_expr);
@@ -6197,10 +6213,11 @@ fn identifier(
const main_tokens = tree.nodes.items(.main_token);
const ident_token = main_tokens[ident];
- const ident_name = try astgen.identifierTokenString(ident_token);
- if (mem.eql(u8, ident_name, "_")) {
+ const ident_name_raw = tree.tokenSlice(ident_token);
+ if (mem.eql(u8, ident_name_raw, "_")) {
return astgen.failNode(ident, "'_' used as an identifier without @\"_\" syntax", .{});
}
+ const ident_name = try astgen.identifierTokenString(ident_token);
if (simple_types.get(ident_name)) |zir_const_ref| {
return rvalue(gz, rl, zir_const_ref, ident);
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
index 232dd942cc..540c37c549 100644
--- a/test/compile_errors.zig
+++ b/test/compile_errors.zig
@@ -2130,8 +2130,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = x;
\\}
, &[_][]const u8{
- "tmp.zig:3:13: error: structs and unions, not enums, support field alignment",
- "tmp.zig:1:16: note: consider 'union(enum)' here",
+ "tmp.zig:3:7: error: expected ',', found 'align'",
});
ctx.objErrStage1("bad alignment type",
@@ -3765,8 +3764,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\ return _;
\\}
, &[_][]const u8{
- "tmp.zig:2:5: error: '_' used as an identifier without @\"_\" syntax",
- "tmp.zig:3:12: error: '_' used as an identifier without @\"_\" syntax",
+ "tmp.zig:2:9: error: '_' used as an identifier without @\"_\" syntax",
});
ctx.objErrStage1("`_` should not be usable inside for",
@@ -4908,7 +4906,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\export fn entry() void { a(); }
, &[_][]const u8{
"tmp.zig:2:1: error: redeclaration of 'a'",
- "tmp.zig:1:1: error: other declaration here",
+ "tmp.zig:1:1: note: other declaration here",
});
ctx.objErrStage1("unreachable with return",
@@ -5218,6 +5216,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\ .z = 4,
\\ .y = 2,
\\ };
+ \\ _ = a;
\\}
, &[_][]const u8{
"tmp.zig:9:17: error: missing field: 'x'",
@@ -7549,13 +7548,15 @@ pub fn addCases(ctx: *TestContext) !void {
\\ };
\\
\\ for ([_]Mode { Mode.Debug, Mode.ReleaseSafe, Mode.ReleaseFast }) |mode| {
+ \\ _ = mode;
\\ inline for (tests) |test_case| {
\\ const foo = test_case.filename ++ ".zig";
+ \\ _ = foo;
\\ }
\\ }
\\}
, &[_][]const u8{
- "tmp.zig:37:29: error: cannot store runtime value in compile time variable",
+ "tmp.zig:38:29: error: cannot store runtime value in compile time variable",
});
ctx.objErrStage1("invalid legacy unicode escape",
@@ -7980,6 +7981,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\};
\\export fn foo() void {
\\ const fieldOffset = @offsetOf(Empty, "val",);
+ \\ _ = fieldOffset;
\\}
, &[_][]const u8{
"tmp.zig:5:42: error: zero-bit field 'val' in struct 'Empty' has no offset",
@@ -7991,6 +7993,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\};
\\export fn foo() void {
\\ const fieldOffset = @bitOffsetOf(Empty, "val",);
+ \\ _ = fieldOffset;
\\}
, &[_][]const u8{
"tmp.zig:5:45: error: zero-bit field 'val' in struct 'Empty' has no offset",
@@ -8004,6 +8007,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\comptime {
\\ var foo = Foo {.Baz = {}};
\\ const bar_val = foo.Bar;
+ \\ _ = bar_val;
\\}
, &[_][]const u8{
"tmp.zig:7:24: error: accessing union field 'Bar' while field 'Baz' is set",
@@ -8119,6 +8123,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\ var x: *const i32 = &w;
\\ var y: *[1]i32 = x;
\\ y[0] += 1;
+ \\ _ = byte;
\\}
, &[_][]const u8{
"tmp.zig:4:22: error: expected type '*[1]i32', found '*const i32'",
@@ -8145,6 +8150,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\export fn f2() void {
\\ var x: anyerror!i32 = error.Bad;
\\ for ("hello") |_| returns() else unreachable;
+ \\ _ = x;
\\}
, &[_][]const u8{
"tmp.zig:5:30: error: expression value is ignored",
@@ -8154,6 +8160,7 @@ pub fn addCases(ctx: *TestContext) !void {
ctx.objErrStage1("aligned variable of zero-bit type",
\\export fn f() void {
\\ var s: struct {} align(4) = undefined;
+ \\ _ = s;
\\}
, &[_][]const u8{
"tmp.zig:2:5: error: variable 's' of zero-bit type 'struct:2:12' has no in-memory representation, it cannot be aligned",
@@ -8637,7 +8644,7 @@ pub fn addCases(ctx: *TestContext) !void {
});
ctx.objErrStage1("issue #5221: invalid struct init type referenced by @typeInfo and passed into function",
- \\fn ignore(comptime param: anytype) void {}
+ \\fn ignore(comptime param: anytype) void {_ = param;}
\\
\\export fn foo() void {
\\ const MyStruct = struct {
From 41336acb0bb89dd23ef9c49b15d91a847f6796bc Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Thu, 1 Jul 2021 16:21:38 -0700
Subject: [PATCH 10/15] AstGen: detect redeclaration of function parameters
Also improve redeclaration error message to include the category of
variable.
---
.../protocols/simple_network_protocol.zig | 8 +-
src/AstGen.zig | 216 +++++++++---------
2 files changed, 113 insertions(+), 111 deletions(-)
diff --git a/lib/std/os/uefi/protocols/simple_network_protocol.zig b/lib/std/os/uefi/protocols/simple_network_protocol.zig
index 8b643d2765..1cd93bc491 100644
--- a/lib/std/os/uefi/protocols/simple_network_protocol.zig
+++ b/lib/std/os/uefi/protocols/simple_network_protocol.zig
@@ -57,13 +57,13 @@ pub const SimpleNetworkProtocol = extern struct {
}
/// Modifies or resets the current station address, if supported.
- pub fn stationAddress(self: *const SimpleNetworkProtocol, reset: bool, new: ?*const MacAddress) Status {
- return self._station_address(self, reset, new);
+ pub fn stationAddress(self: *const SimpleNetworkProtocol, reset_flag: bool, new: ?*const MacAddress) Status {
+ return self._station_address(self, reset_flag, new);
}
/// Resets or collects the statistics on a network interface.
- pub fn statistics(self: *const SimpleNetworkProtocol, reset_: bool, statistics_size: ?*usize, statistics_table: ?*NetworkStatistics) Status {
- return self._statistics(self, reset_, statistics_size, statistics_table);
+ pub fn statistics(self: *const SimpleNetworkProtocol, reset_flag: bool, statistics_size: ?*usize, statistics_table: ?*NetworkStatistics) Status {
+ return self._statistics(self, reset_flag, statistics_size, statistics_table);
}
/// Converts a multicast IP address to a multicast HW MAC address.
diff --git a/src/AstGen.zig b/src/AstGen.zig
index 1e9abda660..c38ba755e7 100644
--- a/src/AstGen.zig
+++ b/src/AstGen.zig
@@ -2216,25 +2216,15 @@ fn checkUsed(
.gen_zir => scope = scope.cast(GenZir).?.parent,
.local_val => {
const s = scope.cast(Scope.LocalVal).?;
- switch (s.used) {
- .used => {},
- .fn_param => return astgen.failTok(s.token_src, "unused function parameter", .{}),
- .constant => return astgen.failTok(s.token_src, "unused local constant", .{}),
- .variable => unreachable,
- .loop_index => unreachable,
- .capture => return astgen.failTok(s.token_src, "unused capture", .{}),
+ if (!s.used) {
+ return astgen.failTok(s.token_src, "unused {s}", .{@tagName(s.id_cat)});
}
scope = s.parent;
},
.local_ptr => {
const s = scope.cast(Scope.LocalPtr).?;
- switch (s.used) {
- .used => {},
- .fn_param => unreachable,
- .constant => return astgen.failTok(s.token_src, "unused local constant", .{}),
- .variable => return astgen.failTok(s.token_src, "unused local variable", .{}),
- .loop_index => return astgen.failTok(s.token_src, "unused loop index capture", .{}),
- .capture => unreachable,
+ if (!s.used) {
+ return astgen.failTok(s.token_src, "unused {s}", .{@tagName(s.id_cat)});
}
scope = s.parent;
},
@@ -2280,63 +2270,7 @@ fn varDecl(
}
const ident_name = try astgen.identAsString(name_token);
- // Local variables shadowing detection, including function parameters.
- {
- var s = scope;
- while (true) switch (s.tag) {
- .local_val => {
- const local_val = s.cast(Scope.LocalVal).?;
- if (local_val.name == ident_name) {
- const name = try gpa.dupe(u8, mem.spanZ(astgen.nullTerminatedString(ident_name)));
- defer gpa.free(name);
- return astgen.failTokNotes(name_token, "redeclaration of '{s}'", .{
- name,
- }, &[_]u32{
- try astgen.errNoteTok(
- local_val.token_src,
- "previously declared here",
- .{},
- ),
- });
- }
- s = local_val.parent;
- },
- .local_ptr => {
- const local_ptr = s.cast(Scope.LocalPtr).?;
- if (local_ptr.name == ident_name) {
- const name = try gpa.dupe(u8, mem.spanZ(astgen.nullTerminatedString(ident_name)));
- defer gpa.free(name);
- return astgen.failTokNotes(name_token, "redeclaration of '{s}'", .{
- name,
- }, &[_]u32{
- try astgen.errNoteTok(
- local_ptr.token_src,
- "previously declared here",
- .{},
- ),
- });
- }
- s = local_ptr.parent;
- },
- .namespace => {
- const ns = s.cast(Scope.Namespace).?;
- const decl_node = ns.decls.get(ident_name) orelse {
- s = ns.parent;
- continue;
- };
- const name = try gpa.dupe(u8, mem.spanZ(astgen.nullTerminatedString(ident_name)));
- defer gpa.free(name);
- return astgen.failTokNotes(name_token, "local shadows declaration of '{s}'", .{
- name,
- }, &[_]u32{
- try astgen.errNoteNode(decl_node, "declared here", .{}),
- });
- },
- .gen_zir => s = s.cast(GenZir).?.parent,
- .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,
- .top => break,
- };
- }
+ try astgen.detectLocalShadowing(scope, ident_name, name_token);
if (var_decl.ast.init_node == 0) {
return astgen.failNode(node, "variables must be initialized", .{});
@@ -2369,7 +2303,7 @@ fn varDecl(
.name = ident_name,
.inst = init_inst,
.token_src = name_token,
- .used = .constant,
+ .id_cat = .@"local constant",
};
return &sub_scope.base;
}
@@ -2438,7 +2372,7 @@ fn varDecl(
.name = ident_name,
.inst = init_inst,
.token_src = name_token,
- .used = .constant,
+ .id_cat = .@"local constant",
};
return &sub_scope.base;
}
@@ -2468,7 +2402,7 @@ fn varDecl(
.ptr = init_scope.rl_ptr,
.token_src = name_token,
.maybe_comptime = true,
- .used = .constant,
+ .id_cat = .@"local constant",
};
return &sub_scope.base;
},
@@ -2525,7 +2459,7 @@ fn varDecl(
.ptr = var_data.alloc,
.token_src = name_token,
.maybe_comptime = is_comptime,
- .used = .variable,
+ .id_cat = .@"local variable",
};
return &sub_scope.base;
},
@@ -3028,7 +2962,7 @@ fn fnDecl(
const param_name = try astgen.identAsString(name_token);
// Create an arg instruction. This is needed to emit a semantic analysis
// error for shadowing decls.
- // TODO emit a compile error here for shadowing locals.
+ try astgen.detectLocalShadowing(params_scope, param_name, name_token);
const arg_inst = try fn_gz.addStrTok(.arg, param_name, name_token);
const sub_scope = try astgen.arena.create(Scope.LocalVal);
sub_scope.* = .{
@@ -3037,7 +2971,7 @@ fn fnDecl(
.name = param_name,
.inst = arg_inst,
.token_src = name_token,
- .used = .fn_param,
+ .id_cat = .@"function parameter",
};
params_scope = &sub_scope.base;
@@ -4701,7 +4635,7 @@ fn orelseCatchExpr(
.name = err_name,
.inst = try then_scope.addUnNode(unwrap_code_op, operand, node),
.token_src = payload,
- .used = .capture,
+ .id_cat = .@"capture",
};
break :blk &err_val_scope.base;
};
@@ -4993,7 +4927,7 @@ fn ifExpr(
.name = ident_name,
.inst = payload_inst,
.token_src = payload_token,
- .used = .capture,
+ .id_cat = .@"capture",
};
break :s &payload_val_scope.base;
} else {
@@ -5015,7 +4949,7 @@ fn ifExpr(
.name = ident_name,
.inst = payload_inst,
.token_src = ident_token,
- .used = .capture,
+ .id_cat = .@"capture",
};
break :s &payload_val_scope.base;
} else {
@@ -5056,7 +4990,7 @@ fn ifExpr(
.name = ident_name,
.inst = payload_inst,
.token_src = error_token,
- .used = .capture,
+ .id_cat = .@"capture",
};
break :s &payload_val_scope.base;
} else {
@@ -5250,7 +5184,7 @@ fn whileExpr(
.name = ident_name,
.inst = payload_inst,
.token_src = payload_token,
- .used = .capture,
+ .id_cat = .@"capture",
};
break :s &payload_val_scope.base;
} else {
@@ -5272,7 +5206,7 @@ fn whileExpr(
.name = ident_name,
.inst = payload_inst,
.token_src = ident_token,
- .used = .capture,
+ .id_cat = .@"capture",
};
break :s &payload_val_scope.base;
} else {
@@ -5329,7 +5263,7 @@ fn whileExpr(
.name = ident_name,
.inst = payload_inst,
.token_src = error_token,
- .used = .capture,
+ .id_cat = .@"capture",
};
break :s &payload_val_scope.base;
} else {
@@ -5468,7 +5402,7 @@ fn forExpr(
.name = name_str_index,
.inst = payload_inst,
.token_src = ident,
- .used = .capture,
+ .id_cat = .@"capture",
};
payload_sub_scope = &payload_val_scope.base;
} else if (is_ptr) {
@@ -5492,7 +5426,7 @@ fn forExpr(
.ptr = index_ptr,
.token_src = index_token,
.maybe_comptime = is_inline,
- .used = .loop_index,
+ .id_cat = .@"loop index capture",
};
break :blk &index_scope.base;
};
@@ -5737,7 +5671,7 @@ fn switchExpr(
.name = capture_name,
.inst = capture,
.token_src = payload_token,
- .used = .capture,
+ .id_cat = .@"capture",
};
break :blk &capture_val_scope.base;
};
@@ -5831,7 +5765,7 @@ fn switchExpr(
.name = capture_name,
.inst = capture,
.token_src = payload_token,
- .used = .capture,
+ .id_cat = .@"capture",
};
break :blk &capture_val_scope.base;
};
@@ -6261,7 +6195,7 @@ fn identifier(
const local_val = s.cast(Scope.LocalVal).?;
if (local_val.name == name_str_index) {
- local_val.used = .used;
+ local_val.used = true;
// Captures of non-locals need to be emitted as decl_val or decl_ref.
// This *might* be capturable depending on if it is comptime known.
if (!hit_namespace) {
@@ -6273,7 +6207,7 @@ fn identifier(
.local_ptr => {
const local_ptr = s.cast(Scope.LocalPtr).?;
if (local_ptr.name == name_str_index) {
- local_ptr.used = .used;
+ local_ptr.used = true;
if (hit_namespace) {
if (local_ptr.maybe_comptime)
break
@@ -6609,7 +6543,7 @@ fn asmExpr(
.local_val => {
const local_val = s.cast(Scope.LocalVal).?;
if (local_val.name == str_index) {
- local_val.used = .used;
+ local_val.used = true;
break;
}
s = local_val.parent;
@@ -6617,7 +6551,7 @@ fn asmExpr(
.local_ptr => {
const local_ptr = s.cast(Scope.LocalPtr).?;
if (local_ptr.name == str_index) {
- local_ptr.used = .used;
+ local_ptr.used = true;
break;
}
s = local_ptr.parent;
@@ -6968,7 +6902,7 @@ fn builtinCall(
.local_val => {
const local_val = s.cast(Scope.LocalVal).?;
if (local_val.name == decl_name) {
- local_val.used = .used;
+ local_val.used = true;
break;
}
s = local_val.parent;
@@ -6978,7 +6912,7 @@ fn builtinCall(
if (local_ptr.name == decl_name) {
if (!local_ptr.maybe_comptime)
return astgen.failNode(params[0], "unable to export runtime-known value", .{});
- local_ptr.used = .used;
+ local_ptr.used = true;
break;
}
s = local_ptr.parent;
@@ -8545,15 +8479,15 @@ const Scope = struct {
top,
};
- // either .used or the type of the var/constant
- const Used = enum {
- fn_param,
- constant,
- variable,
- loop_index,
- capture,
- used,
+ /// The category of identifier. These tag names are user-visible in compile errors.
+ const IdCat = enum {
+ @"function parameter",
+ @"local constant",
+ @"local variable",
+ @"loop index capture",
+ @"capture",
};
+
/// This is always a `const` local and importantly the `inst` is a value type, not a pointer.
/// This structure lives as long as the AST generation of the Block
/// node that contains the variable.
@@ -8568,8 +8502,9 @@ const Scope = struct {
token_src: ast.TokenIndex,
/// String table index.
name: u32,
- /// has this variable been referenced?
- used: Used,
+ id_cat: IdCat,
+ /// Track whether the name has been referenced.
+ used: bool = false,
};
/// This could be a `const` or `var` local. It has a pointer instead of a value.
@@ -8586,10 +8521,12 @@ const Scope = struct {
token_src: ast.TokenIndex,
/// String table index.
name: u32,
- /// true means we find out during Sema whether the value is comptime. false means it is already known at AstGen the value is runtime-known.
+ id_cat: IdCat,
+ /// true means we find out during Sema whether the value is comptime.
+ /// false means it is already known at AstGen the value is runtime-known.
maybe_comptime: bool,
- /// has this variable been referenced?
- used: Used,
+ /// Track whether the name has been referenced.
+ used: bool = false,
};
const Defer = struct {
@@ -9680,6 +9617,71 @@ fn declareNewName(
}
}
+/// Local variables shadowing detection, including function parameters.
+fn detectLocalShadowing(
+ astgen: *AstGen,
+ scope: *Scope,
+ ident_name: u32,
+ name_token: ast.TokenIndex,
+) !void {
+ const gpa = astgen.gpa;
+
+ var s = scope;
+ while (true) switch (s.tag) {
+ .local_val => {
+ const local_val = s.cast(Scope.LocalVal).?;
+ if (local_val.name == ident_name) {
+ const name = try gpa.dupe(u8, mem.spanZ(astgen.nullTerminatedString(ident_name)));
+ defer gpa.free(name);
+ return astgen.failTokNotes(name_token, "redeclaration of {s} '{s}'", .{
+ @tagName(local_val.id_cat), name,
+ }, &[_]u32{
+ try astgen.errNoteTok(
+ local_val.token_src,
+ "previously declared here",
+ .{},
+ ),
+ });
+ }
+ s = local_val.parent;
+ },
+ .local_ptr => {
+ const local_ptr = s.cast(Scope.LocalPtr).?;
+ if (local_ptr.name == ident_name) {
+ const name = try gpa.dupe(u8, mem.spanZ(astgen.nullTerminatedString(ident_name)));
+ defer gpa.free(name);
+ return astgen.failTokNotes(name_token, "redeclaration of {s} '{s}'", .{
+ @tagName(local_ptr.id_cat), name,
+ }, &[_]u32{
+ try astgen.errNoteTok(
+ local_ptr.token_src,
+ "previously declared here",
+ .{},
+ ),
+ });
+ }
+ s = local_ptr.parent;
+ },
+ .namespace => {
+ const ns = s.cast(Scope.Namespace).?;
+ const decl_node = ns.decls.get(ident_name) orelse {
+ s = ns.parent;
+ continue;
+ };
+ const name = try gpa.dupe(u8, mem.spanZ(astgen.nullTerminatedString(ident_name)));
+ defer gpa.free(name);
+ return astgen.failTokNotes(name_token, "local shadows declaration of '{s}'", .{
+ name,
+ }, &[_]u32{
+ try astgen.errNoteNode(decl_node, "declared here", .{}),
+ });
+ },
+ .gen_zir => s = s.cast(GenZir).?.parent,
+ .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,
+ .top => break,
+ };
+}
+
fn advanceSourceCursor(astgen: *AstGen, source: []const u8, end: usize) void {
var i = astgen.source_offset;
var line = astgen.source_line;
From 7a2e0d98109d39f06400dfbc03c12695557100c6 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Thu, 1 Jul 2021 17:28:21 -0700
Subject: [PATCH 11/15] AstGen: cleanups to pass more compile error test cases
---
lib/std/zig/ast.zig | 2 +
lib/std/zig/tokenizer.zig | 10 ++-
src/AstGen.zig | 33 +++++---
src/stage1/astgen.cpp | 14 ++--
src/stage1/ir.cpp | 12 +--
test/cases.zig | 4 +-
test/compile_errors.zig | 165 ++++++++++++++++++--------------------
test/stage2/cbe.zig | 12 +--
test/stage2/darwin.zig | 2 +-
9 files changed, 134 insertions(+), 120 deletions(-)
diff --git a/lib/std/zig/ast.zig b/lib/std/zig/ast.zig
index 8eefe4fb22..abcb29f8b5 100644
--- a/lib/std/zig/ast.zig
+++ b/lib/std/zig/ast.zig
@@ -135,6 +135,8 @@ pub const Tree = struct {
const token_tags = tree.tokens.items(.tag);
switch (parse_error.tag) {
.asterisk_after_ptr_deref => {
+ // Note that the token will point at the `.*` but ideally the source
+ // location would point to the `*` after the `.*`.
return stream.writeAll("'.*' cannot be followed by '*'. Are you missing a space?");
},
.decl_between_fields => {
diff --git a/lib/std/zig/tokenizer.zig b/lib/std/zig/tokenizer.zig
index 1025af5a71..46d022f8bb 100644
--- a/lib/std/zig/tokenizer.zig
+++ b/lib/std/zig/tokenizer.zig
@@ -708,12 +708,18 @@ pub const Tokenizer = struct {
self.checkLiteralCharacter();
}
},
- '\n', '\r' => break, // Look for this error later.
+ '\n' => {
+ result.tag = .invalid;
+ break;
+ },
else => self.checkLiteralCharacter(),
},
.string_literal_backslash => switch (c) {
- '\n', '\r' => break, // Look for this error later.
+ '\n' => {
+ result.tag = .invalid;
+ break;
+ },
else => {
state = .string_literal;
},
diff --git a/src/AstGen.zig b/src/AstGen.zig
index c38ba755e7..4e3473629b 100644
--- a/src/AstGen.zig
+++ b/src/AstGen.zig
@@ -1704,7 +1704,7 @@ fn checkLabelRedefinition(astgen: *AstGen, parent_scope: *Scope, label: ast.Toke
}, &[_]u32{
try astgen.errNoteTok(
prev_label.token,
- "previous definition is here",
+ "previous definition here",
.{},
),
});
@@ -4002,7 +4002,18 @@ fn containerDecl(
return astgen.failTok(comptime_token, "enum fields cannot be marked comptime", .{});
}
if (member.ast.type_expr != 0) {
- return astgen.failNode(member.ast.type_expr, "enum fields do not have types", .{});
+ return astgen.failNodeNotes(
+ member.ast.type_expr,
+ "enum fields do not have types",
+ .{},
+ &[_]u32{
+ try astgen.errNoteNode(
+ node,
+ "consider 'union(enum)' here to make it a tagged union",
+ .{},
+ ),
+ },
+ );
}
// Alignment expressions in enums are caught by the parser.
assert(member.ast.align_expr == 0);
@@ -4520,7 +4531,7 @@ fn tryExpr(
return astgen.failNode(node, "invalid 'try' outside function scope", .{});
};
- if (parent_gz.in_defer) return astgen.failNode(node, "'try' is not allowed inside defer expression", .{});
+ if (parent_gz.in_defer) return astgen.failNode(node, "'try' not allowed inside defer expression", .{});
var block_scope = parent_gz.makeSubBlock(scope);
block_scope.setBreakResultLoc(rl);
@@ -5526,7 +5537,7 @@ fn switchExpr(
&[_]u32{
try astgen.errNoteTok(
src,
- "previous else prong is here",
+ "previous else prong here",
.{},
),
},
@@ -5539,12 +5550,12 @@ fn switchExpr(
&[_]u32{
try astgen.errNoteTok(
case_src,
- "else prong is here",
+ "else prong here",
.{},
),
try astgen.errNoteTok(
some_underscore,
- "'_' prong is here",
+ "'_' prong here",
.{},
),
},
@@ -5567,7 +5578,7 @@ fn switchExpr(
&[_]u32{
try astgen.errNoteTok(
src,
- "previous '_' prong is here",
+ "previous '_' prong here",
.{},
),
},
@@ -5580,12 +5591,12 @@ fn switchExpr(
&[_]u32{
try astgen.errNoteTok(
some_else,
- "else prong is here",
+ "else prong here",
.{},
),
try astgen.errNoteTok(
case_src,
- "'_' prong is here",
+ "'_' prong here",
.{},
),
},
@@ -9638,7 +9649,7 @@ fn detectLocalShadowing(
}, &[_]u32{
try astgen.errNoteTok(
local_val.token_src,
- "previously declared here",
+ "previous declaration here",
.{},
),
});
@@ -9655,7 +9666,7 @@ fn detectLocalShadowing(
}, &[_]u32{
try astgen.errNoteTok(
local_ptr.token_src,
- "previously declared here",
+ "previous declaration here",
.{},
),
});
diff --git a/src/stage1/astgen.cpp b/src/stage1/astgen.cpp
index a95d0af9de..5cad78d120 100644
--- a/src/stage1/astgen.cpp
+++ b/src/stage1/astgen.cpp
@@ -3169,7 +3169,7 @@ ZigVar *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_scope,
if (existing_var->var_type == nullptr || !type_is_invalid(existing_var->var_type)) {
ErrorMsg *msg = add_node_error(codegen, node,
buf_sprintf("redeclaration of variable '%s'", buf_ptr(name)));
- add_error_note(codegen, msg, existing_var->decl_node, buf_sprintf("previous declaration is here"));
+ add_error_note(codegen, msg, existing_var->decl_node, buf_sprintf("previous declaration here"));
}
variable_entry->var_type = codegen->builtin_types.entry_invalid;
} else {
@@ -3191,7 +3191,7 @@ ZigVar *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_scope,
if (want_err_msg) {
ErrorMsg *msg = add_node_error(codegen, node,
buf_sprintf("redefinition of '%s'", buf_ptr(name)));
- add_error_note(codegen, msg, tld->source_node, buf_sprintf("previous definition is here"));
+ add_error_note(codegen, msg, tld->source_node, buf_sprintf("previous definition here"));
}
variable_entry->var_type = codegen->builtin_types.entry_invalid;
}
@@ -3247,7 +3247,7 @@ static bool is_duplicate_label(CodeGen *g, Scope *scope, AstNode *node, Buf *nam
Buf *this_block_name = scope->id == ScopeIdBlock ? ((ScopeBlock *)scope)->name : ((ScopeLoop *)scope)->name;
if (this_block_name != nullptr && buf_eql_buf(name, this_block_name)) {
ErrorMsg *msg = add_node_error(g, node, buf_sprintf("redeclaration of label '%s'", buf_ptr(name)));
- add_error_note(g, msg, scope->source_node, buf_sprintf("previous declaration is here"));
+ add_error_note(g, msg, scope->source_node, buf_sprintf("previous declaration here"));
return true;
}
}
@@ -7026,7 +7026,7 @@ static IrInstSrc *astgen_switch_expr(Stage1AstGen *ag, Scope *scope, AstNode *no
ErrorMsg *msg = add_node_error(ag->codegen, prong_node,
buf_sprintf("multiple else prongs in switch expression"));
add_error_note(ag->codegen, msg, else_prong,
- buf_sprintf("previous else prong is here"));
+ buf_sprintf("previous else prong here"));
return ag->codegen->invalid_inst_src;
}
else_prong = prong_node;
@@ -7037,7 +7037,7 @@ static IrInstSrc *astgen_switch_expr(Stage1AstGen *ag, Scope *scope, AstNode *no
ErrorMsg *msg = add_node_error(ag->codegen, prong_node,
buf_sprintf("multiple '_' prongs in switch expression"));
add_error_note(ag->codegen, msg, underscore_prong,
- buf_sprintf("previous '_' prong is here"));
+ buf_sprintf("previous '_' prong here"));
return ag->codegen->invalid_inst_src;
}
underscore_prong = prong_node;
@@ -7049,10 +7049,10 @@ static IrInstSrc *astgen_switch_expr(Stage1AstGen *ag, Scope *scope, AstNode *no
buf_sprintf("else and '_' prong in switch expression"));
if (underscore_prong == prong_node)
add_error_note(ag->codegen, msg, else_prong,
- buf_sprintf("else prong is here"));
+ buf_sprintf("else prong here"));
else
add_error_note(ag->codegen, msg, underscore_prong,
- buf_sprintf("'_' prong is here"));
+ buf_sprintf("'_' prong here"));
return ag->codegen->invalid_inst_src;
}
ResultLocPeer *this_peer_result_loc = create_peer_result(peer_parent);
diff --git a/src/stage1/ir.cpp b/src/stage1/ir.cpp
index 0c915f5c35..accc1c43f8 100644
--- a/src/stage1/ir.cpp
+++ b/src/stage1/ir.cpp
@@ -11097,7 +11097,7 @@ static IrInstGen *ir_analyze_instruction_export(IrAnalyze *ira, IrInstSrcExport
AstNode *other_export_node = entry->value->source_node;
ErrorMsg *msg = ir_add_error(ira, &instruction->base.base,
buf_sprintf("exported symbol collision: '%s'", buf_ptr(symbol_name)));
- add_error_note(ira->codegen, msg, other_export_node, buf_sprintf("other symbol is here"));
+ add_error_note(ira->codegen, msg, other_export_node, buf_sprintf("other symbol here"));
return ira->codegen->invalid_inst_gen;
}
@@ -11403,7 +11403,7 @@ static IrInstGen *ir_analyze_instruction_extern(IrAnalyze *ira, IrInstSrcExtern
AstNode *other_extern_node = entry->value->source_node;
ErrorMsg *msg = ir_add_error(ira, &instruction->base.base,
buf_sprintf("extern symbol collision: '%s'", buf_ptr(symbol_name)));
- add_error_note(ira->codegen, msg, other_extern_node, buf_sprintf("other symbol is here"));
+ add_error_note(ira->codegen, msg, other_extern_node, buf_sprintf("other symbol here"));
return ira->codegen->invalid_inst_gen;
}
@@ -21732,7 +21732,7 @@ static IrInstGen *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira,
ErrorMsg *msg = ir_add_error(ira, &start_value->base,
buf_sprintf("duplicate switch value: '%s.%s'", buf_ptr(&switch_type->name),
buf_ptr(enum_field->name)));
- add_error_note(ira->codegen, msg, prev_node, buf_sprintf("other value is here"));
+ add_error_note(ira->codegen, msg, prev_node, buf_sprintf("other value here"));
}
bigint_incr(&field_index);
}
@@ -21818,7 +21818,7 @@ static IrInstGen *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira,
Buf *err_name = &ira->codegen->errors_by_index.at(start_index)->name;
ErrorMsg *msg = ir_add_error(ira, &start_value->base,
buf_sprintf("duplicate switch value: '%s.%s'", buf_ptr(&switch_type->name), buf_ptr(err_name)));
- add_error_note(ira->codegen, msg, prev_node, buf_sprintf("other value is here"));
+ add_error_note(ira->codegen, msg, prev_node, buf_sprintf("other value here"));
}
field_prev_uses[start_index] = start_value->base.source_node;
}
@@ -21880,7 +21880,7 @@ static IrInstGen *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira,
start_value->base.source_node);
if (prev_node != nullptr) {
ErrorMsg *msg = ir_add_error(ira, &start_value->base, buf_sprintf("duplicate switch value"));
- add_error_note(ira->codegen, msg, prev_node, buf_sprintf("previous value is here"));
+ add_error_note(ira->codegen, msg, prev_node, buf_sprintf("previous value here"));
return ira->codegen->invalid_inst_gen;
}
}
@@ -21965,7 +21965,7 @@ static IrInstGen *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira,
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"));
+ add_error_note(ira->codegen, msg, entry->value->base.source_node, buf_sprintf("previous value here"));
prevs.deinit();
return ira->codegen->invalid_inst_gen;
}
diff --git a/test/cases.zig b/test/cases.zig
index 7655120157..8d463a4ba5 100644
--- a/test/cases.zig
+++ b/test/cases.zig
@@ -25,7 +25,7 @@ pub fn addCases(ctx: *TestContext) !void {
var case = ctx.exe("hello world with updates", linux_x64);
case.addError("", &[_][]const u8{
- ":93:9: error: struct 'test_case.test_case' has no member named 'main'",
+ ":93:9: error: struct 'tmp.tmp' has no member named 'main'",
});
// Incorrect return type
@@ -965,7 +965,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\ defer return a();
\\}
, &[_][]const u8{
- ":7:8: error: try is not allowed inside defer expression",
+ ":7:8: error: 'try' not allowed inside defer expression",
":10:8: error: cannot return from defer expression",
});
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
index 540c37c549..bc2c8f83fb 100644
--- a/test/compile_errors.zig
+++ b/test/compile_errors.zig
@@ -614,11 +614,11 @@ pub fn addCases(ctx: *TestContext) !void {
\\}
, &[_][]const u8{
"tmp.zig:2:12: error: redefinition of label 'blk'",
- "tmp.zig:2:5: note: previous definition is here",
+ "tmp.zig:2:5: note: previous definition here",
"tmp.zig:5:26: error: redefinition of label 'blk'",
- "tmp.zig:5:5: note: previous definition is here",
+ "tmp.zig:5:5: note: previous definition here",
"tmp.zig:8:46: error: redefinition of label 'blk'",
- "tmp.zig:8:5: note: previous definition is here",
+ "tmp.zig:8:5: note: previous definition here",
"tmp.zig:11:5: error: unused block label",
"tmp.zig:14:5: error: unused while loop label",
"tmp.zig:17:5: error: unused for loop label",
@@ -4261,7 +4261,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\}
, &[_][]const u8{
"tmp.zig:5:14: error: duplicate switch value: '@typeInfo(@typeInfo(@TypeOf(foo)).Fn.return_type.?).ErrorUnion.error_set.Foo'",
- "tmp.zig:3:14: note: other value is here",
+ "tmp.zig:3:14: note: other value here",
});
ctx.objErrStage1("invalid cast from integral type to enum",
@@ -4932,8 +4932,8 @@ pub fn addCases(ctx: *TestContext) !void {
});
ctx.objErrStage1("wrong number of arguments",
- \\export fn a() void {
- \\ b(1);
+ \\export fn d() void {
+ \\ e(1);
\\}
\\fn b(a: i32, b: i32, c: i32) void { _ = a; _ = b; _ = c; }
, &[_][]const u8{
@@ -4988,7 +4988,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\}
\\export fn entry() void { f(1, 2); }
, &[_][]const u8{
- "tmp.zig:1:15: error: redeclaration of parameter 'a'",
+ "tmp.zig:1:15: error: redeclaration of function parameter 'a'",
"tmp.zig:1:6: note: previous declaration here",
});
@@ -4998,7 +4998,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\ var a = 0;
\\}
, &[_][]const u8{
- "tmp.zig:3:9: error: redeclaration of local const 'a'",
+ "tmp.zig:3:9: error: redeclaration of local constant 'a'",
"tmp.zig:2:11: note: previous declaration here",
});
@@ -5008,7 +5008,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\}
\\export fn entry() void { f(1); }
, &[_][]const u8{
- "tmp.zig:2:11: error: redeclaration of parameter 'a'",
+ "tmp.zig:2:11: error: redeclaration of function parameter 'a'",
"tmp.zig:1:6: note: previous declaration here",
});
@@ -5295,7 +5295,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = foo;
\\}
, &[_][]const u8{
- "tmp.zig:1:21: error: type '[3]u16' does not support struct initialization syntax",
+ "tmp.zig:1:13: error: initializing array with struct syntax",
});
ctx.objErrStage1("type variables must be constant",
@@ -5307,23 +5307,28 @@ pub fn addCases(ctx: *TestContext) !void {
"tmp.zig:1:1: error: variable of type 'type' must be constant",
});
- ctx.objErrStage1("variables shadowing types",
+ ctx.objErrStage1("parameter shadowing global",
\\const Foo = struct {};
- \\const Bar = struct {};
- \\
- \\fn f(Foo: i32) void {
- \\ var Bar : i32 = undefined;
- \\ _ = Bar;
- \\}
- \\
+ \\fn f(Foo: i32) void {}
\\export fn entry() void {
\\ f(1234);
\\}
, &[_][]const u8{
- "tmp.zig:4:6: error: redefinition of 'Foo'",
- "tmp.zig:1:1: note: previous definition is here",
- "tmp.zig:5:5: error: redefinition of 'Bar'",
- "tmp.zig:2:1: note: previous definition is here",
+ "tmp.zig:2:6: error: local shadows declaration of 'Foo'",
+ "tmp.zig:1:1: note: declared here",
+ });
+
+ ctx.objErrStage1("local variable shadowing global",
+ \\const Foo = struct {};
+ \\const Bar = struct {};
+ \\
+ \\export fn entry() void {
+ \\ var Bar : i32 = undefined;
+ \\ _ = Bar;
+ \\}
+ , &[_][]const u8{
+ "tmp.zig:5:9: error: local shadows declaration of 'Bar'",
+ "tmp.zig:2:1: note: declared here",
});
ctx.objErrStage1("switch expression - missing enumeration prong",
@@ -5366,7 +5371,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\export fn entry() usize { return @sizeOf(@TypeOf(f)); }
, &[_][]const u8{
"tmp.zig:13:15: error: duplicate switch value",
- "tmp.zig:10:15: note: other value is here",
+ "tmp.zig:10:15: note: other value here",
});
ctx.objErrStage1("switch expression - duplicate enumeration prong when else present",
@@ -5390,7 +5395,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\export fn entry() usize { return @sizeOf(@TypeOf(f)); }
, &[_][]const u8{
"tmp.zig:13:15: error: duplicate switch value",
- "tmp.zig:10:15: note: other value is here",
+ "tmp.zig:10:15: note: other value here",
});
ctx.objErrStage1("switch expression - multiple else prongs",
@@ -5431,7 +5436,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\export fn entry() usize { return @sizeOf(@TypeOf(foo)); }
, &[_][]const u8{
"tmp.zig:6:9: error: duplicate switch value",
- "tmp.zig:5:14: note: previous value is here",
+ "tmp.zig:5:14: note: previous value here",
});
ctx.objErrStage1("switch expression - duplicate type",
@@ -5447,7 +5452,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\export fn entry() usize { return @sizeOf(@TypeOf(foo(u32, 0))); }
, &[_][]const u8{
"tmp.zig:6:9: error: duplicate switch value",
- "tmp.zig:4:9: note: previous value is here",
+ "tmp.zig:4:9: note: previous value here",
});
ctx.objErrStage1("switch expression - duplicate type (struct alias)",
@@ -5467,7 +5472,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\export fn entry() usize { return @sizeOf(@TypeOf(foo(u32, 0))); }
, &[_][]const u8{
"tmp.zig:10:9: error: duplicate switch value",
- "tmp.zig:8:9: note: previous value is here",
+ "tmp.zig:8:9: note: previous value here",
});
ctx.objErrStage1("switch expression - switch on pointer type with no else",
@@ -5662,10 +5667,9 @@ pub fn addCases(ctx: *TestContext) !void {
ctx.objErrStage1("normal string with newline",
\\const foo = "a
\\b";
- \\
- \\export fn entry() usize { return @sizeOf(@TypeOf(foo)); }
, &[_][]const u8{
- "tmp.zig:1:15: error: newline not allowed in string literal",
+ "tmp.zig:1:13: error: expected expression, found 'invalid'",
+ "tmp.zig:1:15: note: invalid byte here",
});
ctx.objErrStage1("invalid comparison for function pointers",
@@ -6595,7 +6599,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\
\\export fn entry() usize { return @sizeOf(@TypeOf(testTrickyDefer)); }
, &[_][]const u8{
- "tmp.zig:4:11: error: 'try' is not allowed inside defer expression",
+ "tmp.zig:4:11: error: 'try' not allowed inside defer expression",
});
ctx.objErrStage1("assign too big number to u16",
@@ -6976,7 +6980,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\}
, &[_][]const u8{
"tmp.zig:9:17: error: redefinition of 'Self'",
- "tmp.zig:5:9: note: previous definition is here",
+ "tmp.zig:5:9: note: previous definition here",
});
ctx.objErrStage1("while expected bool, got optional",
@@ -7692,24 +7696,18 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = x;
\\}
, &[_][]const u8{
- "tmp.zig:2:14: error: untagged union field assignment",
- "tmp.zig:1:24: note: consider 'union(enum)' here",
+ "tmp.zig:1:24: error: explicitly valued tagged union missing integer tag type",
+ "tmp.zig:2:14: note: tag value specified here",
});
ctx.objErrStage1("enum with 0 fields",
\\const Foo = enum {};
- \\export fn entry() usize {
- \\ return @sizeOf(Foo);
- \\}
, &[_][]const u8{
- "tmp.zig:1:13: error: enums must have 1 or more fields",
+ "tmp.zig:1:13: error: enum declarations must have at least one tag",
});
ctx.objErrStage1("union with 0 fields",
\\const Foo = union {};
- \\export fn entry() usize {
- \\ return @sizeOf(Foo);
- \\}
, &[_][]const u8{
"tmp.zig:1:13: error: union declarations must have at least one tag",
});
@@ -7817,13 +7815,9 @@ pub fn addCases(ctx: *TestContext) !void {
\\ B,
\\ C,
\\};
- \\export fn entry() void {
- \\ var b = Letter.B;
- \\ _ = b;
- \\}
, &[_][]const u8{
- "tmp.zig:2:8: error: structs and unions, not enums, support field types",
- "tmp.zig:1:16: note: consider 'union(enum)' here",
+ "tmp.zig:2:8: error: enum fields do not have types",
+ "tmp.zig:1:16: note: consider 'union(enum)' here to make it a tagged union",
});
ctx.objErrStage1("struct field missing type",
@@ -8231,9 +8225,9 @@ pub fn addCases(ctx: *TestContext) !void {
\\}
, &[_][]const u8{
"tmp.zig:3:28: error: parameter of opaque type 'FooType' not allowed",
- "tmp.zig:7:28: error: parameter of type '(null)' not allowed",
- "tmp.zig:10:11: error: parameter of opaque type 'FooType' not allowed",
- "tmp.zig:15:11: error: parameter of type '(null)' not allowed",
+ "tmp.zig:8:28: error: parameter of type '(null)' not allowed",
+ "tmp.zig:12:11: error: parameter of opaque type 'FooType' not allowed",
+ "tmp.zig:17:11: error: parameter of type '(null)' not allowed",
});
ctx.objErrStage1( // fixed bug #2032
@@ -8268,8 +8262,8 @@ pub fn addCases(ctx: *TestContext) !void {
\\}
, &[_][]const u8{
"tmp.zig:3:19: error: use of undefined value here causes undefined behavior",
- "tmp.zig:8:23: error: use of undefined value here causes undefined behavior",
- "tmp.zig:14:23: error: use of undefined value here causes undefined behavior",
+ "tmp.zig:9:23: error: use of undefined value here causes undefined behavior",
+ "tmp.zig:16:23: error: use of undefined value here causes undefined behavior",
});
ctx.objErrStage1("issue #3818: bitcast from parray/slice to u16",
@@ -8285,8 +8279,8 @@ pub fn addCases(ctx: *TestContext) !void {
\\}
, &[_][]const u8{
"tmp.zig:3:42: error: unable to @bitCast from pointer type '*[2]u8'",
- "tmp.zig:7:32: error: destination type 'u16' has size 2 but source type '[]const u8' has size 16",
- "tmp.zig:7:37: note: referenced here",
+ "tmp.zig:8:32: error: destination type 'u16' has size 2 but source type '[]const u8' has size 16",
+ "tmp.zig:8:37: note: referenced here",
});
// issue #7810
@@ -8361,12 +8355,12 @@ pub fn addCases(ctx: *TestContext) !void {
\\}
, &[_][]const u8{
":4:29: error: slice-sentinel is out of bounds",
- ":11:29: error: slice-sentinel is out of bounds",
- ":18:29: error: slice-sentinel is out of bounds",
- ":25:29: error: slice-sentinel is out of bounds",
- ":32:29: error: slice-sentinel is out of bounds",
- ":39:29: error: slice-sentinel is out of bounds",
- ":46:29: error: slice-sentinel is out of bounds",
+ ":12:29: error: slice-sentinel is out of bounds",
+ ":20:29: error: slice-sentinel is out of bounds",
+ ":28:29: error: slice-sentinel is out of bounds",
+ ":36:29: error: slice-sentinel is out of bounds",
+ ":44:29: error: slice-sentinel is out of bounds",
+ ":52:29: error: slice-sentinel is out of bounds",
});
ctx.objErrStage1("comptime slice-sentinel is out of bounds (terminated)",
@@ -8427,12 +8421,12 @@ pub fn addCases(ctx: *TestContext) !void {
\\}
, &[_][]const u8{
":4:29: error: out of bounds slice",
- ":11:29: error: out of bounds slice",
- ":18:29: error: out of bounds slice",
- ":25:29: error: out of bounds slice",
- ":32:29: error: out of bounds slice",
- ":39:29: error: out of bounds slice",
- ":46:29: error: out of bounds slice",
+ ":12:29: error: out of bounds slice",
+ ":20:29: error: out of bounds slice",
+ ":28:29: error: out of bounds slice",
+ ":36:29: error: out of bounds slice",
+ ":44:29: error: out of bounds slice",
+ ":52:29: error: out of bounds slice",
});
ctx.objErrStage1("comptime slice-sentinel does not match memory at target index (unterminated)",
@@ -8493,12 +8487,12 @@ pub fn addCases(ctx: *TestContext) !void {
\\}
, &[_][]const u8{
":4:29: error: slice-sentinel does not match memory at target index",
- ":11:29: error: slice-sentinel does not match memory at target index",
- ":18:29: error: slice-sentinel does not match memory at target index",
- ":25:29: error: slice-sentinel does not match memory at target index",
- ":32:29: error: slice-sentinel does not match memory at target index",
- ":39:29: error: slice-sentinel does not match memory at target index",
- ":46:29: error: slice-sentinel does not match memory at target index",
+ ":12:29: error: slice-sentinel does not match memory at target index",
+ ":20:29: error: slice-sentinel does not match memory at target index",
+ ":28:29: error: slice-sentinel does not match memory at target index",
+ ":36:29: error: slice-sentinel does not match memory at target index",
+ ":44:29: error: slice-sentinel does not match memory at target index",
+ ":52:29: error: slice-sentinel does not match memory at target index",
});
ctx.objErrStage1("comptime slice-sentinel does not match memory at target index (terminated)",
@@ -8559,12 +8553,12 @@ pub fn addCases(ctx: *TestContext) !void {
\\}
, &[_][]const u8{
":4:29: error: slice-sentinel does not match memory at target index",
- ":11:29: error: slice-sentinel does not match memory at target index",
- ":18:29: error: slice-sentinel does not match memory at target index",
- ":25:29: error: slice-sentinel does not match memory at target index",
- ":32:29: error: slice-sentinel does not match memory at target index",
- ":39:29: error: slice-sentinel does not match memory at target index",
- ":46:29: error: slice-sentinel does not match memory at target index",
+ ":12:29: error: slice-sentinel does not match memory at target index",
+ ":20:29: error: slice-sentinel does not match memory at target index",
+ ":28:29: error: slice-sentinel does not match memory at target index",
+ ":36:29: error: slice-sentinel does not match memory at target index",
+ ":44:29: error: slice-sentinel does not match memory at target index",
+ ":52:29: error: slice-sentinel does not match memory at target index",
});
ctx.objErrStage1("comptime slice-sentinel does not match target-sentinel",
@@ -8625,12 +8619,12 @@ pub fn addCases(ctx: *TestContext) !void {
\\}
, &[_][]const u8{
":4:29: error: slice-sentinel does not match target-sentinel",
- ":11:29: error: slice-sentinel does not match target-sentinel",
- ":18:29: error: slice-sentinel does not match target-sentinel",
- ":25:29: error: slice-sentinel does not match target-sentinel",
- ":32:29: error: slice-sentinel does not match target-sentinel",
- ":39:29: error: slice-sentinel does not match target-sentinel",
- ":46:29: error: slice-sentinel does not match target-sentinel",
+ ":12:29: error: slice-sentinel does not match target-sentinel",
+ ":20:29: error: slice-sentinel does not match target-sentinel",
+ ":28:29: error: slice-sentinel does not match target-sentinel",
+ ":36:29: error: slice-sentinel does not match target-sentinel",
+ ":44:29: error: slice-sentinel does not match target-sentinel",
+ ":52:29: error: slice-sentinel does not match target-sentinel",
});
ctx.objErrStage1("issue #4207: coerce from non-terminated-slice to terminated-pointer",
@@ -8774,7 +8768,8 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = sequence;
\\}
, &[_][]const u8{
- "tmp.zig:2:30: error: `.*` cannot be followed by `*`. Are you missing a space?",
+ // Ideally this would be column 30 but it's not very important.
+ "tmp.zig:2:28: error: `.*` cannot be followed by `*`. Are you missing a space?",
});
ctx.objErrStage1("Issue #9165: windows tcp server compilation error",
diff --git a/test/stage2/cbe.zig b/test/stage2/cbe.zig
index fd55015dd5..158fe0dfd4 100644
--- a/test/stage2/cbe.zig
+++ b/test/stage2/cbe.zig
@@ -525,7 +525,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\}
, &.{
":3:21: error: missing struct field: x",
- ":1:15: note: struct 'test_case.Point' declared here",
+ ":1:15: note: struct 'tmp.Point' declared here",
});
case.addError(
\\const Point = struct { x: i32, y: i32 };
@@ -538,7 +538,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\ return p.y - p.x - p.x;
\\}
, &.{
- ":6:10: error: no field named 'z' in struct 'test_case.Point'",
+ ":6:10: error: no field named 'z' in struct 'tmp.Point'",
":1:15: note: struct declared here",
});
case.addCompareOutput(
@@ -716,7 +716,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = @intToEnum(E, 3);
\\}
, &.{
- ":3:9: error: enum 'test_case.E' has no tag with value 3",
+ ":3:9: error: enum 'tmp.E' has no tag with value 3",
":1:11: note: enum declared here",
});
@@ -732,7 +732,7 @@ pub fn addCases(ctx: *TestContext) !void {
, &.{
":4:5: error: switch must handle all possibilities",
":4:5: note: unhandled enumeration value: 'b'",
- ":1:11: note: enum 'test_case.E' declared here",
+ ":1:11: note: enum 'tmp.E' declared here",
});
case.addError(
@@ -787,7 +787,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = E.d;
\\}
, &.{
- ":3:10: error: enum 'test_case.E' has no member named 'd'",
+ ":3:10: error: enum 'tmp.E' has no member named 'd'",
":1:11: note: enum declared here",
});
@@ -798,7 +798,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = x;
\\}
, &.{
- ":3:17: error: enum 'test_case.E' has no field named 'd'",
+ ":3:17: error: enum 'tmp.E' has no field named 'd'",
":1:11: note: enum declared here",
});
}
diff --git a/test/stage2/darwin.zig b/test/stage2/darwin.zig
index 0bb2562385..d40fcbc5ac 100644
--- a/test/stage2/darwin.zig
+++ b/test/stage2/darwin.zig
@@ -14,7 +14,7 @@ pub fn addCases(ctx: *TestContext) !void {
{
var case = ctx.exe("hello world with updates", target);
case.addError("", &[_][]const u8{
- ":93:9: error: struct 'test_case.test_case' has no member named 'main'",
+ ":93:9: error: struct 'tmp.tmp' has no member named 'main'",
});
// Incorrect return type
From c5c23db6278332044c0606d78419000b68185e0c Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 2 Jul 2021 12:33:05 -0700
Subject: [PATCH 12/15] tokenizer: clean up invalid token error
It now displays the byte with proper printability handling. This makes
the relevant compile error test case no longer a regression in quality
from stage1 to stage2.
---
lib/std/zig/tokenizer.zig | 3 ++-
src/Module.zig | 5 ++--
src/main.zig | 24 +++++++++++-------
src/stage1/analyze.cpp | 6 ++---
test/cases.zig | 10 ++++----
test/compile_errors.zig | 53 ++++++++++++++++++++-------------------
test/stage2/cbe.zig | 1 +
7 files changed, 56 insertions(+), 46 deletions(-)
diff --git a/lib/std/zig/tokenizer.zig b/lib/std/zig/tokenizer.zig
index 46d022f8bb..3008aecdc3 100644
--- a/lib/std/zig/tokenizer.zig
+++ b/lib/std/zig/tokenizer.zig
@@ -551,8 +551,9 @@ pub const Tokenizer = struct {
},
else => {
result.tag = .invalid;
+ result.loc.end = self.index;
self.index += 1;
- break;
+ return result;
},
},
diff --git a/src/Module.zig b/src/Module.zig
index 2e421ea65b..4b82a6df07 100644
--- a/src/Module.zig
+++ b/src/Module.zig
@@ -2480,11 +2480,12 @@ pub fn astGenFile(mod: *Module, file: *Scope.File) !void {
};
if (token_tags[parse_err.token] == .invalid) {
const bad_off = @intCast(u32, file.tree.tokenSlice(parse_err.token).len);
+ const byte_abs = token_starts[parse_err.token] + bad_off;
try mod.errNoteNonLazy(.{
.file_scope = file,
.parent_decl_node = 0,
- .lazy = .{ .byte_abs = token_starts[parse_err.token] + bad_off },
- }, err_msg, "invalid byte here", .{});
+ .lazy = .{ .byte_abs = byte_abs },
+ }, err_msg, "invalid byte: '{'}'", .{ std.zig.fmtEscapes(source[byte_abs..][0..1]) });
}
{
diff --git a/src/main.zig b/src/main.zig
index f4ca11a96a..37044d0b99 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -233,7 +233,7 @@ pub fn mainArgs(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v
} else if (mem.eql(u8, cmd, "build")) {
return cmdBuild(gpa, arena, cmd_args);
} else if (mem.eql(u8, cmd, "fmt")) {
- return cmdFmt(gpa, cmd_args);
+ return cmdFmt(gpa, arena, cmd_args);
} else if (mem.eql(u8, cmd, "libc")) {
return cmdLibC(gpa, cmd_args);
} else if (mem.eql(u8, cmd, "init-exe")) {
@@ -3039,12 +3039,13 @@ const Fmt = struct {
check_ast: bool,
color: Color,
gpa: *Allocator,
+ arena: *Allocator,
out_buffer: std.ArrayList(u8),
const SeenMap = std.AutoHashMap(fs.File.INode, void);
};
-pub fn cmdFmt(gpa: *Allocator, args: []const []const u8) !void {
+pub fn cmdFmt(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !void {
var color: Color = .auto;
var stdin_flag: bool = false;
var check_flag: bool = false;
@@ -3102,7 +3103,7 @@ pub fn cmdFmt(gpa: *Allocator, args: []const []const u8) !void {
defer tree.deinit(gpa);
for (tree.errors) |parse_error| {
- try printErrMsgToStdErr(gpa, parse_error, tree, "", color);
+ try printErrMsgToStdErr(gpa, arena, parse_error, tree, "", color);
}
var has_ast_error = false;
if (check_ast_flag) {
@@ -3170,6 +3171,7 @@ pub fn cmdFmt(gpa: *Allocator, args: []const []const u8) !void {
var fmt = Fmt{
.gpa = gpa,
+ .arena = arena,
.seen = Fmt.SeenMap.init(gpa),
.any_error = false,
.check_ast = check_ast_flag,
@@ -3293,7 +3295,7 @@ fn fmtPathFile(
defer tree.deinit(fmt.gpa);
for (tree.errors) |parse_error| {
- try printErrMsgToStdErr(fmt.gpa, parse_error, tree, file_path, fmt.color);
+ try printErrMsgToStdErr(fmt.gpa, fmt.arena, parse_error, tree, file_path, fmt.color);
}
if (tree.errors.len != 0) {
fmt.any_error = true;
@@ -3374,6 +3376,7 @@ fn fmtPathFile(
fn printErrMsgToStdErr(
gpa: *mem.Allocator,
+ arena: *mem.Allocator,
parse_error: ast.Error,
tree: ast.Tree,
path: []const u8,
@@ -3395,11 +3398,14 @@ fn printErrMsgToStdErr(
if (token_tags[parse_error.token] == .invalid) {
const bad_off = @intCast(u32, tree.tokenSlice(parse_error.token).len);
+ const byte_offset = @intCast(u32, start_loc.line_start) + bad_off;
notes_buffer[notes_len] = .{
.src = .{
.src_path = path,
- .msg = "invalid byte here",
- .byte_offset = @intCast(u32, start_loc.line_start) + bad_off,
+ .msg = try std.fmt.allocPrint(arena, "invalid byte: '{'}'", .{
+ std.zig.fmtEscapes(tree.source[byte_offset..][0..1]),
+ }),
+ .byte_offset = byte_offset,
.line = @intCast(u32, start_loc.line),
.column = @intCast(u32, start_loc.column) + bad_off,
.source_line = source_line,
@@ -3943,7 +3949,7 @@ pub fn cmdAstCheck(
defer file.tree.deinit(gpa);
for (file.tree.errors) |parse_error| {
- try printErrMsgToStdErr(gpa, parse_error, file.tree, file.sub_file_path, color);
+ try printErrMsgToStdErr(gpa, arena, parse_error, file.tree, file.sub_file_path, color);
}
if (file.tree.errors.len != 0) {
process.exit(1);
@@ -4069,7 +4075,7 @@ pub fn cmdChangelist(
defer file.tree.deinit(gpa);
for (file.tree.errors) |parse_error| {
- try printErrMsgToStdErr(gpa, parse_error, file.tree, old_source_file, .auto);
+ try printErrMsgToStdErr(gpa, arena, parse_error, file.tree, old_source_file, .auto);
}
if (file.tree.errors.len != 0) {
process.exit(1);
@@ -4108,7 +4114,7 @@ pub fn cmdChangelist(
defer new_tree.deinit(gpa);
for (new_tree.errors) |parse_error| {
- try printErrMsgToStdErr(gpa, parse_error, new_tree, new_source_file, .auto);
+ try printErrMsgToStdErr(gpa, arena, parse_error, new_tree, new_source_file, .auto);
}
if (new_tree.errors.len != 0) {
process.exit(1);
diff --git a/src/stage1/analyze.cpp b/src/stage1/analyze.cpp
index 3fb0cb55b7..5daad0213d 100644
--- a/src/stage1/analyze.cpp
+++ b/src/stage1/analyze.cpp
@@ -3915,7 +3915,7 @@ static void add_top_level_decl(CodeGen *g, ScopeDecls *decls_scope, Tld *tld) {
}
}
ErrorMsg *msg = add_node_error(g, tld->source_node, buf_sprintf("redefinition of '%s'", buf_ptr(tld->name)));
- add_error_note(g, msg, other_tld->source_node, buf_sprintf("previous definition is here"));
+ add_error_note(g, msg, other_tld->source_node, buf_sprintf("previous definition here"));
return;
}
@@ -4176,7 +4176,7 @@ ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf
if (existing_var->var_type == nullptr || !type_is_invalid(existing_var->var_type)) {
ErrorMsg *msg = add_node_error(g, source_node,
buf_sprintf("redeclaration of variable '%s'", buf_ptr(name)));
- add_error_note(g, msg, existing_var->decl_node, buf_sprintf("previous declaration is here"));
+ add_error_note(g, msg, existing_var->decl_node, buf_sprintf("previous declaration here"));
}
variable_entry->var_type = g->builtin_types.entry_invalid;
} else {
@@ -4205,7 +4205,7 @@ ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf
if (want_err_msg) {
ErrorMsg *msg = add_node_error(g, source_node,
buf_sprintf("redefinition of '%s'", buf_ptr(name)));
- add_error_note(g, msg, tld->source_node, buf_sprintf("previous definition is here"));
+ add_error_note(g, msg, tld->source_node, buf_sprintf("previous definition here"));
}
variable_entry->var_type = g->builtin_types.entry_invalid;
}
diff --git a/test/cases.zig b/test/cases.zig
index 8d463a4ba5..fa66db8e34 100644
--- a/test/cases.zig
+++ b/test/cases.zig
@@ -1039,8 +1039,8 @@ pub fn addCases(ctx: *TestContext) !void {
\\ var i: u32 = 10;
\\}
, &[_][]const u8{
- ":3:9: error: redeclaration of 'i'",
- ":2:9: note: previously declared here",
+ ":3:9: error: redeclaration of local variable 'i'",
+ ":2:9: note: previous declaration here",
});
case.addError(
\\var testing: i64 = 10;
@@ -1061,8 +1061,8 @@ pub fn addCases(ctx: *TestContext) !void {
\\ };
\\}
, &[_][]const u8{
- ":5:19: error: redeclaration of 'c'",
- ":4:19: note: previously declared here",
+ ":5:19: error: redeclaration of local constant 'c'",
+ ":4:19: note: previous declaration here",
});
}
@@ -1214,7 +1214,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\}
, &[_][]const u8{
":2:11: error: redefinition of label 'blk'",
- ":2:5: note: previous definition is here",
+ ":2:5: note: previous definition here",
});
}
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
index bc2c8f83fb..6ad5c16348 100644
--- a/test/compile_errors.zig
+++ b/test/compile_errors.zig
@@ -1507,7 +1507,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\}
, &[_][]const u8{
"tmp.zig:2:21: error: expected expression, found 'invalid'",
- "tmp.zig:2:28: note: invalid byte here",
+ "tmp.zig:2:28: note: invalid byte: 'a'",
});
ctx.objErrStage1("invalid exponent in float literal - 2",
@@ -1517,7 +1517,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\}
, &[_][]const u8{
"tmp.zig:2:21: error: expected expression, found 'invalid'",
- "tmp.zig:2:29: note: invalid byte here",
+ "tmp.zig:2:29: note: invalid byte: 'F'",
});
ctx.objErrStage1("invalid underscore placement in float literal - 1",
@@ -1527,7 +1527,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\}
, &[_][]const u8{
"tmp.zig:2:21: error: expected expression, found 'invalid'",
- "tmp.zig:2:23: note: invalid byte here",
+ "tmp.zig:2:23: note: invalid byte: '_'",
});
ctx.objErrStage1("invalid underscore placement in float literal - 2",
@@ -1537,7 +1537,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\}
, &[_][]const u8{
"tmp.zig:2:21: error: expected expression, found 'invalid'",
- "tmp.zig:2:23: note: invalid byte here",
+ "tmp.zig:2:23: note: invalid byte: '.'",
});
ctx.objErrStage1("invalid underscore placement in float literal - 3",
@@ -1547,7 +1547,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\}
, &[_][]const u8{
"tmp.zig:2:21: error: expected expression, found 'invalid'",
- "tmp.zig:2:25: note: invalid byte here",
+ "tmp.zig:2:25: note: invalid byte: ';'",
});
ctx.objErrStage1("invalid underscore placement in float literal - 4",
@@ -1557,7 +1557,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\}
, &[_][]const u8{
"tmp.zig:2:21: error: expected expression, found 'invalid'",
- "tmp.zig:2:25: note: invalid byte here",
+ "tmp.zig:2:25: note: invalid byte: '_'",
});
ctx.objErrStage1("invalid underscore placement in float literal - 5",
@@ -1567,7 +1567,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\}
, &[_][]const u8{
"tmp.zig:2:21: error: expected expression, found 'invalid'",
- "tmp.zig:2:26: note: invalid byte here",
+ "tmp.zig:2:26: note: invalid byte: '_'",
});
ctx.objErrStage1("invalid underscore placement in float literal - 6",
@@ -1577,7 +1577,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\}
, &[_][]const u8{
"tmp.zig:2:21: error: expected expression, found 'invalid'",
- "tmp.zig:2:26: note: invalid byte here",
+ "tmp.zig:2:26: note: invalid byte: '_'",
});
ctx.objErrStage1("invalid underscore placement in float literal - 7",
@@ -1587,7 +1587,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\}
, &[_][]const u8{
"tmp.zig:2:21: error: expected expression, found 'invalid'",
- "tmp.zig:2:28: note: invalid byte here",
+ "tmp.zig:2:28: note: invalid byte: ';'",
});
ctx.objErrStage1("invalid underscore placement in float literal - 9",
@@ -1597,7 +1597,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\}
, &[_][]const u8{
"tmp.zig:2:21: error: expected expression, found 'invalid'",
- "tmp.zig:2:23: note: invalid byte here",
+ "tmp.zig:2:23: note: invalid byte: '_'",
});
ctx.objErrStage1("invalid underscore placement in float literal - 10",
@@ -1607,7 +1607,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\}
, &[_][]const u8{
"tmp.zig:2:21: error: expected expression, found 'invalid'",
- "tmp.zig:2:25: note: invalid byte here",
+ "tmp.zig:2:25: note: invalid byte: '_'",
});
ctx.objErrStage1("invalid underscore placement in float literal - 11",
@@ -1617,7 +1617,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\}
, &[_][]const u8{
"tmp.zig:2:21: error: expected expression, found 'invalid'",
- "tmp.zig:2:28: note: invalid byte here",
+ "tmp.zig:2:28: note: invalid byte: '_'",
});
ctx.objErrStage1("invalid underscore placement in float literal - 12",
@@ -1627,7 +1627,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\}
, &[_][]const u8{
"tmp.zig:2:21: error: expected expression, found 'invalid'",
- "tmp.zig:2:23: note: invalid byte here",
+ "tmp.zig:2:23: note: invalid byte: 'x'",
});
ctx.objErrStage1("invalid underscore placement in float literal - 13",
@@ -1637,7 +1637,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\}
, &[_][]const u8{
"tmp.zig:2:21: error: expected expression, found 'invalid'",
- "tmp.zig:2:23: note: invalid byte here",
+ "tmp.zig:2:23: note: invalid byte: '_'",
});
ctx.objErrStage1("invalid underscore placement in float literal - 14",
@@ -1647,7 +1647,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\}
, &[_][]const u8{
"tmp.zig:2:21: error: expected expression, found 'invalid'",
- "tmp.zig:2:27: note: invalid byte here",
+ "tmp.zig:2:27: note: invalid byte: 'p'",
});
ctx.objErrStage1("invalid underscore placement in int literal - 1",
@@ -1657,7 +1657,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\}
, &[_][]const u8{
"tmp.zig:2:21: error: expected expression, found 'invalid'",
- "tmp.zig:2:26: note: invalid byte here",
+ "tmp.zig:2:26: note: invalid byte: ';'",
});
ctx.objErrStage1("invalid underscore placement in int literal - 2",
@@ -1667,7 +1667,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\}
, &[_][]const u8{
"tmp.zig:2:21: error: expected expression, found 'invalid'",
- "tmp.zig:2:28: note: invalid byte here",
+ "tmp.zig:2:28: note: invalid byte: ';'",
});
ctx.objErrStage1("invalid underscore placement in int literal - 3",
@@ -1677,7 +1677,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\}
, &[_][]const u8{
"tmp.zig:2:21: error: expected expression, found 'invalid'",
- "tmp.zig:2:28: note: invalid byte here",
+ "tmp.zig:2:28: note: invalid byte: ';'",
});
ctx.objErrStage1("invalid underscore placement in int literal - 4",
@@ -1687,7 +1687,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\}
, &[_][]const u8{
"tmp.zig:2:21: error: expected expression, found 'invalid'",
- "tmp.zig:2:28: note: invalid byte here",
+ "tmp.zig:2:28: note: invalid byte: ';'",
});
ctx.objErrStage1("comptime struct field, no init value",
@@ -4932,10 +4932,10 @@ pub fn addCases(ctx: *TestContext) !void {
});
ctx.objErrStage1("wrong number of arguments",
- \\export fn d() void {
- \\ e(1);
+ \\export fn a() void {
+ \\ c(1);
\\}
- \\fn b(a: i32, b: i32, c: i32) void { _ = a; _ = b; _ = c; }
+ \\fn c(d: i32, e: i32, f: i32) void { _ = d; _ = e; _ = f; }
, &[_][]const u8{
"tmp.zig:2:6: error: expected 3 argument(s), found 1",
});
@@ -5669,7 +5669,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\b";
, &[_][]const u8{
"tmp.zig:1:13: error: expected expression, found 'invalid'",
- "tmp.zig:1:15: note: invalid byte here",
+ "tmp.zig:1:15: note: invalid byte: '\\n'",
});
ctx.objErrStage1("invalid comparison for function pointers",
@@ -7569,7 +7569,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\}
, &[_][]const u8{
"tmp.zig:2:15: error: expected expression, found 'invalid'",
- "tmp.zig:2:18: note: invalid byte here",
+ "tmp.zig:2:18: note: invalid byte: '1'",
});
ctx.objErrStage1("invalid empty unicode escape",
@@ -7584,7 +7584,8 @@ pub fn addCases(ctx: *TestContext) !void {
"fn foo() bool {\r\n" ++
" return true;\r\n" ++
"}\r\n", &[_][]const u8{
- "tmp.zig:1:1: error: invalid character: '\\xff'",
+ "tmp.zig:1:1: error: expected test, comptime, var decl, or container field, found 'invalid'",
+ "tmp.zig:1:1: note: invalid byte: '\\xff'",
});
ctx.objErrStage1("non-printable invalid character with escape alternative", "fn foo() bool {\n" ++
@@ -8769,7 +8770,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\}
, &[_][]const u8{
// Ideally this would be column 30 but it's not very important.
- "tmp.zig:2:28: error: `.*` cannot be followed by `*`. Are you missing a space?",
+ "tmp.zig:2:28: error: '.*' cannot be followed by '*'. Are you missing a space?",
});
ctx.objErrStage1("Issue #9165: windows tcp server compilation error",
diff --git a/test/stage2/cbe.zig b/test/stage2/cbe.zig
index 158fe0dfd4..8f69421fd4 100644
--- a/test/stage2/cbe.zig
+++ b/test/stage2/cbe.zig
@@ -591,6 +591,7 @@ pub fn addCases(ctx: *TestContext) !void {
, &.{
":3:5: error: enum fields cannot be marked comptime",
":8:8: error: enum fields do not have types",
+ ":6:12: note: consider 'union(enum)' here to make it a tagged union",
});
// @enumToInt, @intToEnum, enum literal coercion, field access syntax, comparison, switch
From 5103053977573131d8040a53d9ab3f2afd1b01b0 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 2 Jul 2021 13:26:10 -0700
Subject: [PATCH 13/15] compile errors test harness: support unknown
file/line/column
This gets us 2 more passing compile error test cases.
---
lib/std/fmt.zig | 4 +-
src/test.zig | 90 +++++++++++++++++++++++++----------------
test/compile_errors.zig | 10 ++++-
3 files changed, 66 insertions(+), 38 deletions(-)
diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig
index a1b0781106..22bafd04f1 100644
--- a/lib/std/fmt.zig
+++ b/lib/std/fmt.zig
@@ -362,8 +362,8 @@ pub fn format(
const missing_count = arg_state.args_len - @popCount(ArgSetType, arg_state.used_args);
switch (missing_count) {
0 => unreachable,
- 1 => @compileError("Unused argument in \"" ++ fmt ++ "\""),
- else => @compileError((comptime comptimePrint("{d}", .{missing_count})) ++ " unused arguments in \"" ++ fmt ++ "\""),
+ 1 => @compileError("Unused argument in '" ++ fmt ++ "'"),
+ else => @compileError((comptime comptimePrint("{d}", .{missing_count})) ++ " unused arguments in '" ++ fmt ++ "'"),
}
}
}
diff --git a/src/test.zig b/src/test.zig
index 19135e3d7e..c478694268 100644
--- a/src/test.zig
+++ b/src/test.zig
@@ -37,7 +37,11 @@ const ErrorMsg = union(enum) {
src: struct {
src_path: []const u8,
msg: []const u8,
+ // maxint means match anything
+ // this is a workaround for stage1 compiler bug I ran into when making it ?u32
line: u32,
+ // maxint means match anything
+ // this is a workaround for stage1 compiler bug I ran into when making it ?u32
column: u32,
kind: Kind,
},
@@ -81,13 +85,23 @@ const ErrorMsg = union(enum) {
_ = options;
switch (self) {
.src => |src| {
- return writer.print("{s}:{d}:{d}: {s}: {s}", .{
- src.src_path,
- src.line + 1,
- src.column + 1,
- @tagName(src.kind),
- src.msg,
- });
+ if (!std.mem.eql(u8, src.src_path, "?") or
+ src.line != std.math.maxInt(u32) or
+ src.column != std.math.maxInt(u32))
+ {
+ try writer.print("{s}:", .{src.src_path});
+ if (src.line != std.math.maxInt(u32)) {
+ try writer.print("{d}:", .{src.line + 1});
+ } else {
+ try writer.writeAll("?:");
+ }
+ if (src.column != std.math.maxInt(u32)) {
+ try writer.print("{d}: ", .{src.column + 1});
+ } else {
+ try writer.writeAll("?: ");
+ }
+ }
+ return writer.print("{s}: {s}", .{ @tagName(src.kind), src.msg });
},
.plain => |plain| {
return writer.print("{s}: {s}", .{ @tagName(plain.kind), plain.msg });
@@ -220,8 +234,14 @@ pub const TestContext = struct {
const kind_text = it.next() orelse @panic("missing 'error'/'note'");
const msg = it.rest()[1..]; // skip over the space at end of "error: "
- const line = std.fmt.parseInt(u32, line_text, 10) catch @panic("bad line number");
- const column = std.fmt.parseInt(u32, col_text, 10) catch @panic("bad column number");
+ const line: ?u32 = if (std.mem.eql(u8, line_text, "?"))
+ null
+ else
+ std.fmt.parseInt(u32, line_text, 10) catch @panic("bad line number");
+ const column: ?u32 = if (std.mem.eql(u8, line_text, "?"))
+ null
+ else
+ std.fmt.parseInt(u32, col_text, 10) catch @panic("bad column number");
const kind: ErrorMsg.Kind = if (std.mem.eql(u8, kind_text, " error"))
.@"error"
else if (std.mem.eql(u8, kind_text, " note"))
@@ -229,16 +249,28 @@ pub const TestContext = struct {
else
@panic("expected 'error'/'note'");
- if (line == 0 or column == 0) {
- @panic("line and column must be specified starting at one");
- }
+ const line_0based: u32 = if (line) |n| blk: {
+ if (n == 0) {
+ print("{s}: line must be specified starting at one\n", .{self.name});
+ return;
+ }
+ break :blk n - 1;
+ } else std.math.maxInt(u32);
+
+ const column_0based: u32 = if (column) |n| blk: {
+ if (n == 0) {
+ print("{s}: line must be specified starting at one\n", .{self.name});
+ return;
+ }
+ break :blk n - 1;
+ } else std.math.maxInt(u32);
array[i] = .{
.src = .{
.src_path = src_path,
.msg = msg,
- .line = line - 1,
- .column = column - 1,
+ .line = line_0based,
+ .column = column_0based,
.kind = kind,
},
};
@@ -737,7 +769,7 @@ pub const TestContext = struct {
}
var ok = true;
if (case.expect_exact) {
- var err_iter = ErrLineIter.init(result.stderr);
+ var err_iter = std.mem.split(result.stderr, "\n");
var i: usize = 0;
ok = while (err_iter.next()) |line| : (i += 1) {
if (i >= case_error_list.len) break false;
@@ -940,8 +972,10 @@ pub const TestContext = struct {
std.mem.eql(u8, case_msg.src.src_path, actual_msg.src_path);
if (src_path_ok and
- actual_msg.line == case_msg.src.line and
- actual_msg.column == case_msg.src.column and
+ (case_msg.src.line == std.math.maxInt(u32) or
+ actual_msg.line == case_msg.src.line) and
+ (case_msg.src.column == std.math.maxInt(u32) or
+ actual_msg.column == case_msg.src.column) and
std.mem.eql(u8, case_msg.src.msg, actual_msg.msg) and
case_msg.src.kind == .@"error")
{
@@ -978,8 +1012,10 @@ pub const TestContext = struct {
}
if (ex_tag != .src) continue;
- if (actual_msg.line == case_msg.src.line and
- actual_msg.column == case_msg.src.column and
+ if ((case_msg.src.line == std.math.maxInt(u32) or
+ actual_msg.line == case_msg.src.line) and
+ (case_msg.src.column == std.math.maxInt(u32) or
+ actual_msg.column == case_msg.src.column) and
std.mem.eql(u8, case_msg.src.msg, actual_msg.msg) and
case_msg.src.kind == .note)
{
@@ -1162,19 +1198,3 @@ fn dumpArgs(argv: []const []const u8) void {
}
const tmp_src_path = "tmp.zig";
-
-const ErrLineIter = struct {
- lines: std.mem.SplitIterator,
-
- fn init(input: []const u8) ErrLineIter {
- return ErrLineIter{ .lines = std.mem.split(input, "\n") };
- }
-
- fn next(self: *ErrLineIter) ?[]const u8 {
- while (self.lines.next()) |line| {
- if (std.mem.indexOf(u8, line, tmp_src_path) != null)
- return line;
- }
- return null;
- }
-};
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
index 6ad5c16348..863ff88a5f 100644
--- a/test/compile_errors.zig
+++ b/test/compile_errors.zig
@@ -2,6 +2,14 @@ const std = @import("std");
const TestContext = @import("../src/test.zig").TestContext;
pub fn addCases(ctx: *TestContext) !void {
+ ctx.exeErrStage1("std.fmt error for unused arguments",
+ \\pub fn main() !void {
+ \\ @import("std").debug.print("{d} {d} {d} {d} {d}", .{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15});
+ \\}
+ , &.{
+ "?:?:?: error: 10 unused arguments in '{d} {d} {d} {d} {d}'",
+ });
+
ctx.objErrStage1("lazy pointer with undefined element type",
\\export fn foo() void {
\\ comptime var T: type = undefined;
@@ -6120,7 +6128,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\
\\export fn entry() usize { return @sizeOf(@TypeOf(resource)); }
, &[_][]const u8{
- "tmp.zig:1:29: error: unable to find 'bogus.txt'",
+ "tmp.zig:1:29: error: unable to find '",
});
ctx.objErrStage1("non-const expression in struct literal outside function",
From d979dd9b58f6d5462b009002e0a0eb79f94fb9a7 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 2 Jul 2021 15:27:00 -0700
Subject: [PATCH 14/15] stage2: improve AstGen FileNotFound error message
Partially addresses #9203. It fixes the first case, but not the second
one mentioned in the issue.
---
lib/std/mem.zig | 10 ++++----
src/AstGen.zig | 14 +++++++---
src/Compilation.zig | 57 +++++++++++++++++++++++++++++++----------
src/Module.zig | 2 +-
src/Zir.zig | 17 ++++++++----
src/test.zig | 42 +++++++++++++++++++++++++++---
test/compile_errors.zig | 3 +--
7 files changed, 111 insertions(+), 34 deletions(-)
diff --git a/lib/std/mem.zig b/lib/std/mem.zig
index b7b9d92165..75cb4dd9d0 100644
--- a/lib/std/mem.zig
+++ b/lib/std/mem.zig
@@ -2297,14 +2297,14 @@ pub fn replaceOwned(comptime T: type, allocator: *Allocator, input: []const T, n
}
test "replaceOwned" {
- const allocator = std.heap.page_allocator;
+ const gpa = std.testing.allocator;
- const base_replace = replaceOwned(u8, allocator, "All your base are belong to us", "base", "Zig") catch unreachable;
- defer allocator.free(base_replace);
+ const base_replace = replaceOwned(u8, gpa, "All your base are belong to us", "base", "Zig") catch @panic("out of memory");
+ defer gpa.free(base_replace);
try testing.expect(eql(u8, base_replace, "All your Zig are belong to us"));
- const zen_replace = replaceOwned(u8, allocator, "Favor reading code over writing code.", " code", "") catch unreachable;
- defer allocator.free(zen_replace);
+ const zen_replace = replaceOwned(u8, gpa, "Favor reading code over writing code.", " code", "") catch @panic("out of memory");
+ defer gpa.free(zen_replace);
try testing.expect(eql(u8, zen_replace, "Favor reading over writing."));
}
diff --git a/src/AstGen.zig b/src/AstGen.zig
index 4e3473629b..d511cc13aa 100644
--- a/src/AstGen.zig
+++ b/src/AstGen.zig
@@ -34,8 +34,9 @@ string_table: std.StringHashMapUnmanaged(u32) = .{},
compile_errors: ArrayListUnmanaged(Zir.Inst.CompileErrors.Item) = .{},
/// The topmost block of the current function.
fn_block: ?*GenZir = null,
-/// String table indexes, keeps track of all `@import` operands.
-imports: std.AutoArrayHashMapUnmanaged(u32, void) = .{},
+/// Maps string table indexes to the first `@import` ZIR instruction
+/// that uses this string as the operand.
+imports: std.AutoArrayHashMapUnmanaged(u32, Zir.Inst.Index) = .{},
const InnerError = error{ OutOfMemory, AnalysisFail };
@@ -154,7 +155,7 @@ pub fn generate(gpa: *Allocator, tree: ast.Tree) Allocator.Error!Zir {
astgen.extra.items[imports_index] = astgen.addExtraAssumeCapacity(Zir.Inst.Imports{
.imports_len = @intCast(u32, astgen.imports.count()),
});
- astgen.extra.appendSliceAssumeCapacity(astgen.imports.keys());
+ astgen.extra.appendSliceAssumeCapacity(astgen.imports.values());
}
return Zir{
@@ -6863,8 +6864,13 @@ fn builtinCall(
}
const str_lit_token = main_tokens[operand_node];
const str = try astgen.strLitAsString(str_lit_token);
- try astgen.imports.put(astgen.gpa, str.index, {});
const result = try gz.addStrTok(.import, str.index, str_lit_token);
+ if (gz.refToIndex(result)) |import_inst_index| {
+ const gop = try astgen.imports.getOrPut(astgen.gpa, str.index);
+ if (!gop.found_existing) {
+ gop.value_ptr.* = import_inst_index;
+ }
+ }
return rvalue(gz, rl, result, node);
},
.compile_log => {
diff --git a/src/Compilation.zig b/src/Compilation.zig
index 68a008e0e1..c51f2960d3 100644
--- a/src/Compilation.zig
+++ b/src/Compilation.zig
@@ -1958,7 +1958,7 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
while (self.astgen_work_queue.readItem()) |file| {
self.astgen_wait_group.start();
try self.thread_pool.spawn(workerAstGenFile, .{
- self, file, &zir_prog_node, &self.astgen_wait_group,
+ self, file, &zir_prog_node, &self.astgen_wait_group, .root,
});
}
@@ -2310,11 +2310,20 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
};
}
+const AstGenSrc = union(enum) {
+ root,
+ import: struct {
+ importing_file: *Module.Scope.File,
+ import_inst: Zir.Inst.Index,
+ },
+};
+
fn workerAstGenFile(
comp: *Compilation,
file: *Module.Scope.File,
prog_node: *std.Progress.Node,
wg: *WaitGroup,
+ src: AstGenSrc,
) void {
defer wg.finish();
@@ -2327,7 +2336,7 @@ fn workerAstGenFile(
error.AnalysisFail => return,
else => {
file.status = .retryable_failure;
- comp.reportRetryableAstGenError(file, err) catch |oom| switch (oom) {
+ comp.reportRetryableAstGenError(src, file, err) catch |oom| switch (oom) {
// Swallowing this error is OK because it's implied to be OOM when
// there is a missing `failed_files` error message.
error.OutOfMemory => {},
@@ -2344,8 +2353,9 @@ fn workerAstGenFile(
if (imports_index != 0) {
const imports_len = file.zir.extra[imports_index];
- for (file.zir.extra[imports_index + 1 ..][0..imports_len]) |str_index| {
- const import_path = file.zir.nullTerminatedString(str_index);
+ for (file.zir.extra[imports_index + 1 ..][0..imports_len]) |import_inst| {
+ const inst_data = file.zir.instructions.items(.data)[import_inst].str_tok;
+ const import_path = inst_data.get(file.zir);
const import_result = blk: {
const lock = comp.mutex.acquire();
@@ -2357,9 +2367,13 @@ fn workerAstGenFile(
log.debug("AstGen of {s} has import '{s}'; queuing AstGen of {s}", .{
file.sub_file_path, import_path, import_result.file.sub_file_path,
});
+ const sub_src: AstGenSrc = .{ .import = .{
+ .importing_file = file,
+ .import_inst = import_inst,
+ } };
wg.start();
comp.thread_pool.spawn(workerAstGenFile, .{
- comp, import_result.file, prog_node, wg,
+ comp, import_result.file, prog_node, wg, sub_src,
}) catch {
wg.finish();
continue;
@@ -2570,6 +2584,7 @@ fn reportRetryableCObjectError(
fn reportRetryableAstGenError(
comp: *Compilation,
+ src: AstGenSrc,
file: *Module.Scope.File,
err: anyerror,
) error{OutOfMemory}!void {
@@ -2578,22 +2593,38 @@ fn reportRetryableAstGenError(
file.status = .retryable_failure;
- const src_loc: Module.SrcLoc = .{
- .file_scope = file,
- .parent_decl_node = 0,
- .lazy = .entire_file,
+ const src_loc: Module.SrcLoc = switch (src) {
+ .root => .{
+ .file_scope = file,
+ .parent_decl_node = 0,
+ .lazy = .entire_file,
+ },
+ .import => |info| blk: {
+ const importing_file = info.importing_file;
+ const import_inst = info.import_inst;
+ const inst_data = importing_file.zir.instructions.items(.data)[import_inst].str_tok;
+ break :blk .{
+ .file_scope = importing_file,
+ .parent_decl_node = 0,
+ .lazy = .{ .token_offset = inst_data.src_tok },
+ };
+ },
};
const err_msg = if (file.pkg.root_src_directory.path) |dir_path|
try Module.ErrorMsg.create(
gpa,
src_loc,
- "unable to load {s}" ++ std.fs.path.sep_str ++ "{s}: {s}",
- .{ dir_path, file.sub_file_path, @errorName(err) },
+ "unable to load '{'}" ++ std.fs.path.sep_str ++ "{'}': {s}",
+ .{
+ std.zig.fmtEscapes(dir_path),
+ std.zig.fmtEscapes(file.sub_file_path),
+ @errorName(err),
+ },
)
else
- try Module.ErrorMsg.create(gpa, src_loc, "unable to load {s}: {s}", .{
- file.sub_file_path, @errorName(err),
+ try Module.ErrorMsg.create(gpa, src_loc, "unable to load '{'}': {s}", .{
+ std.zig.fmtEscapes(file.sub_file_path), @errorName(err),
});
errdefer err_msg.destroy(gpa);
diff --git a/src/Module.zig b/src/Module.zig
index 4b82a6df07..b3480532b0 100644
--- a/src/Module.zig
+++ b/src/Module.zig
@@ -2485,7 +2485,7 @@ pub fn astGenFile(mod: *Module, file: *Scope.File) !void {
.file_scope = file,
.parent_decl_node = 0,
.lazy = .{ .byte_abs = byte_abs },
- }, err_msg, "invalid byte: '{'}'", .{ std.zig.fmtEscapes(source[byte_abs..][0..1]) });
+ }, err_msg, "invalid byte: '{'}'", .{std.zig.fmtEscapes(source[byte_abs..][0..1])});
}
{
diff --git a/src/Zir.zig b/src/Zir.zig
index 5d75030711..12ceb85c56 100644
--- a/src/Zir.zig
+++ b/src/Zir.zig
@@ -139,9 +139,15 @@ pub fn renderAsTextToFile(
if (imports_index != 0) {
try fs_file.writeAll("Imports:\n");
const imports_len = scope_file.zir.extra[imports_index];
- for (scope_file.zir.extra[imports_index + 1 ..][0..imports_len]) |str_index| {
- const import_path = scope_file.zir.nullTerminatedString(str_index);
- try fs_file.writer().print(" {s}\n", .{import_path});
+ for (scope_file.zir.extra[imports_index + 1 ..][0..imports_len]) |import_inst| {
+ const inst_data = writer.code.instructions.items(.data)[import_inst].str_tok;
+ const src = inst_data.src();
+ const import_path = inst_data.get(writer.code);
+ try fs_file.writer().print(" @import(\"{}\") ", .{
+ std.zig.fmtEscapes(import_path),
+ });
+ try writer.writeSrc(fs_file.writer(), src);
+ try fs_file.writer().writeAll("\n");
}
}
}
@@ -2767,9 +2773,10 @@ pub const Inst = struct {
};
};
- /// Trailing: for each `imports_len` there is a string table index.
+ /// Trailing: for each `imports_len` there is an instruction index
+ /// to an import instruction.
pub const Imports = struct {
- imports_len: u32,
+ imports_len: Zir.Inst.Index,
};
};
diff --git a/src/test.zig b/src/test.zig
index c478694268..ef37fd0065 100644
--- a/src/test.zig
+++ b/src/test.zig
@@ -699,6 +699,11 @@ pub const TestContext = struct {
arena,
&[_][]const u8{ ".", "zig-cache", "tmp", &tmp.sub_path },
);
+ const tmp_dir_path_plus_slash = try std.fmt.allocPrint(
+ arena,
+ "{s}" ++ std.fs.path.sep_str,
+ .{tmp_dir_path},
+ );
const local_cache_path = try std.fs.path.join(
arena,
&[_][]const u8{ tmp_dir_path, "zig-cache" },
@@ -773,7 +778,14 @@ pub const TestContext = struct {
var i: usize = 0;
ok = while (err_iter.next()) |line| : (i += 1) {
if (i >= case_error_list.len) break false;
- const expected = try std.fmt.allocPrint(arena, "{s}", .{case_error_list[i]});
+ const expected = try std.mem.replaceOwned(
+ u8,
+ arena,
+ try std.fmt.allocPrint(arena, "{s}", .{case_error_list[i]}),
+ "${DIR}",
+ tmp_dir_path_plus_slash,
+ );
+
if (std.mem.indexOf(u8, line, expected) == null) break false;
continue;
} else true;
@@ -789,7 +801,13 @@ pub const TestContext = struct {
}
} else {
for (case_error_list) |msg| {
- const expected = try std.fmt.allocPrint(arena, "{s}", .{msg});
+ const expected = try std.mem.replaceOwned(
+ u8,
+ arena,
+ try std.fmt.allocPrint(arena, "{s}", .{msg}),
+ "${DIR}",
+ tmp_dir_path_plus_slash,
+ );
if (std.mem.indexOf(u8, result.stderr, expected) == null) {
print(
\\
@@ -971,12 +989,20 @@ pub const TestContext = struct {
const src_path_ok = case_msg.src.src_path.len == 0 or
std.mem.eql(u8, case_msg.src.src_path, actual_msg.src_path);
+ const expected_msg = try std.mem.replaceOwned(
+ u8,
+ arena,
+ case_msg.src.msg,
+ "${DIR}",
+ tmp_dir_path_plus_slash,
+ );
+
if (src_path_ok and
(case_msg.src.line == std.math.maxInt(u32) or
actual_msg.line == case_msg.src.line) and
(case_msg.src.column == std.math.maxInt(u32) or
actual_msg.column == case_msg.src.column) and
- std.mem.eql(u8, case_msg.src.msg, actual_msg.msg) and
+ std.mem.eql(u8, expected_msg, actual_msg.msg) and
case_msg.src.kind == .@"error")
{
handled_errors[i] = true;
@@ -1012,11 +1038,19 @@ pub const TestContext = struct {
}
if (ex_tag != .src) continue;
+ const expected_msg = try std.mem.replaceOwned(
+ u8,
+ arena,
+ case_msg.src.msg,
+ "${DIR}",
+ tmp_dir_path_plus_slash,
+ );
+
if ((case_msg.src.line == std.math.maxInt(u32) or
actual_msg.line == case_msg.src.line) and
(case_msg.src.column == std.math.maxInt(u32) or
actual_msg.column == case_msg.src.column) and
- std.mem.eql(u8, case_msg.src.msg, actual_msg.msg) and
+ std.mem.eql(u8, expected_msg, actual_msg.msg) and
case_msg.src.kind == .note)
{
handled_errors[i] = true;
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
index 863ff88a5f..6ce1774ecf 100644
--- a/test/compile_errors.zig
+++ b/test/compile_errors.zig
@@ -4976,9 +4976,8 @@ pub fn addCases(ctx: *TestContext) !void {
ctx.objErrStage1("bad import",
\\const bogus = @import("bogus-does-not-exist.zig",);
- \\export fn entry() void { bogus.bogo(); }
, &[_][]const u8{
- "tmp.zig:1:15: error: unable to find 'bogus-does-not-exist.zig'",
+ "tmp.zig:1:23: error: unable to load '${DIR}bogus-does-not-exist.zig': FileNotFound",
});
ctx.objErrStage1("undeclared identifier",
From a6bf68ccf985787eeac33a97e362d043987905c4 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 2 Jul 2021 16:22:09 -0700
Subject: [PATCH 15/15] langref: fix test cases now that AST Lowering has
priority
---
doc/docgen.zig | 48 ++++++++++++++++++++++++++++++++-------------
doc/langref.html.in | 20 +++++++++++++++----
2 files changed, 50 insertions(+), 18 deletions(-)
diff --git a/doc/docgen.zig b/doc/docgen.zig
index ad13275a4c..1261981af3 100644
--- a/doc/docgen.zig
+++ b/doc/docgen.zig
@@ -8,6 +8,7 @@ const Progress = std.Progress;
const print = std.debug.print;
const mem = std.mem;
const testing = std.testing;
+const Allocator = std.mem.Allocator;
const max_doc_file_size = 10 * 1024 * 1024;
@@ -326,7 +327,7 @@ const Action = enum {
Close,
};
-fn genToc(allocator: *mem.Allocator, tokenizer: *Tokenizer) !Toc {
+fn genToc(allocator: *Allocator, tokenizer: *Tokenizer) !Toc {
var urls = std.StringHashMap(Token).init(allocator);
errdefer urls.deinit();
@@ -630,7 +631,7 @@ fn genToc(allocator: *mem.Allocator, tokenizer: *Tokenizer) !Toc {
};
}
-fn urlize(allocator: *mem.Allocator, input: []const u8) ![]u8 {
+fn urlize(allocator: *Allocator, input: []const u8) ![]u8 {
var buf = std.ArrayList(u8).init(allocator);
defer buf.deinit();
@@ -649,7 +650,7 @@ fn urlize(allocator: *mem.Allocator, input: []const u8) ![]u8 {
return buf.toOwnedSlice();
}
-fn escapeHtml(allocator: *mem.Allocator, input: []const u8) ![]u8 {
+fn escapeHtml(allocator: *Allocator, input: []const u8) ![]u8 {
var buf = std.ArrayList(u8).init(allocator);
defer buf.deinit();
@@ -695,7 +696,7 @@ test "term color" {
testing.expectEqualSlices(u8, "AgreenB", result);
}
-fn termColor(allocator: *mem.Allocator, input: []const u8) ![]u8 {
+fn termColor(allocator: *Allocator, input: []const u8) ![]u8 {
var buf = std.ArrayList(u8).init(allocator);
defer buf.deinit();
@@ -789,8 +790,15 @@ fn isType(name: []const u8) bool {
return false;
}
-fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: anytype, source_token: Token, raw_src: []const u8) !void {
- const src = mem.trim(u8, raw_src, " \n");
+fn tokenizeAndPrintRaw(
+ allocator: *Allocator,
+ docgen_tokenizer: *Tokenizer,
+ out: anytype,
+ source_token: Token,
+ raw_src: []const u8,
+) !void {
+ const src_non_terminated = mem.trim(u8, raw_src, " \n");
+ const src = try allocator.dupeZ(u8, src_non_terminated);
try out.writeAll("");
var tokenizer = std.zig.Tokenizer.init(src);
var index: usize = 0;
@@ -1016,12 +1024,24 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: anytype, source_token:
try out.writeAll("");
}
-fn tokenizeAndPrint(docgen_tokenizer: *Tokenizer, out: anytype, source_token: Token) !void {
+fn tokenizeAndPrint(
+ allocator: *Allocator,
+ docgen_tokenizer: *Tokenizer,
+ out: anytype,
+ source_token: Token,
+) !void {
const raw_src = docgen_tokenizer.buffer[source_token.start..source_token.end];
- return tokenizeAndPrintRaw(docgen_tokenizer, out, source_token, raw_src);
+ return tokenizeAndPrintRaw(allocator, docgen_tokenizer, out, source_token, raw_src);
}
-fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: anytype, zig_exe: []const u8, do_code_tests: bool) !void {
+fn genHtml(
+ allocator: *Allocator,
+ tokenizer: *Tokenizer,
+ toc: *Toc,
+ out: anytype,
+ zig_exe: []const u8,
+ do_code_tests: bool,
+) !void {
var progress = Progress{};
const root_node = try progress.start("Generating docgen examples", toc.nodes.len);
defer root_node.end();
@@ -1048,7 +1068,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: any
},
.Builtin => |tok| {
try out.writeAll("");
- try tokenizeAndPrintRaw(tokenizer, out, tok, builtin_code);
+ try tokenizeAndPrintRaw(allocator, tokenizer, out, tok, builtin_code);
try out.writeAll("");
},
.HeaderOpen => |info| {
@@ -1069,7 +1089,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: any
try out.writeAll("\n");
},
.Syntax => |content_tok| {
- try tokenizeAndPrint(tokenizer, out, content_tok);
+ try tokenizeAndPrint(allocator, tokenizer, out, content_tok);
},
.Code => |code| {
const raw_source = tokenizer.buffer[code.source_token.start..code.source_token.end];
@@ -1078,7 +1098,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: any
try out.print("{s}.zig
", .{code.name});
}
try out.writeAll("");
- try tokenizeAndPrint(tokenizer, out, code.source_token);
+ try tokenizeAndPrint(allocator, tokenizer, out, code.source_token);
try out.writeAll("");
if (!do_code_tests) {
@@ -1497,7 +1517,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: any
}
}
-fn exec(allocator: *mem.Allocator, env_map: *std.BufMap, args: []const []const u8) !ChildProcess.ExecResult {
+fn exec(allocator: *Allocator, env_map: *std.BufMap, args: []const []const u8) !ChildProcess.ExecResult {
const result = try ChildProcess.exec(.{
.allocator = allocator,
.argv = args,
@@ -1521,7 +1541,7 @@ fn exec(allocator: *mem.Allocator, env_map: *std.BufMap, args: []const []const u
return result;
}
-fn getBuiltinCode(allocator: *mem.Allocator, env_map: *std.BufMap, zig_exe: []const u8) ![]const u8 {
+fn getBuiltinCode(allocator: *Allocator, env_map: *std.BufMap, zig_exe: []const u8) ![]const u8 {
const result = try exec(allocator, env_map, &[_][]const u8{ zig_exe, "build-obj", "--show-builtin" });
return result.stdout;
}
diff --git a/doc/langref.html.in b/doc/langref.html.in
index 31de76359e..cd7bc3be5c 100644
--- a/doc/langref.html.in
+++ b/doc/langref.html.in
@@ -3025,7 +3025,7 @@ test "@tagName" {
{#code_begin|obj_err|parameter of type 'Foo' not allowed in function with calling convention 'C'#}
const Foo = enum { a, b, c };
-export fn entry(foo: Foo) void { }
+export fn entry(foo: Foo) void { _ = foo; }
{#code_end#}
For a C-ABI-compatible enum, provide an explicit tag type to
@@ -3346,7 +3346,7 @@ test "call foo" {
Blocks are used to limit the scope of variable declarations:
- {#code_begin|test_err|undeclared identifier#}
+ {#code_begin|test_err|unused local variable#}
test "access variable after block scope" {
{
var x: i32 = 1;
@@ -3377,7 +3377,7 @@ test "labeled break from labeled block expression" {
{#header_open|Shadowing#}
It is never allowed for an identifier to "hide" another one by using the same name:
- {#code_begin|test_err|redefinition#}
+ {#code_begin|test_err|local shadows declaration#}
const pi = 3.14;
test "inside test block" {
@@ -5257,6 +5257,7 @@ test "float widening" {
// Compile time coercion of float to int
test "implicit cast to comptime_int" {
var f: f32 = 54.0 / 5;
+ _ = f;
}
{#code_end#}
{#header_close#}
@@ -5817,6 +5818,7 @@ fn foo(condition: bool) void {
if (condition) f32 else u64,
1234,
5678);
+ _ = result;
}
{#code_end#}
@@ -6313,7 +6315,7 @@ pub fn printValue(self: *Writer, value: anytype) !void {
And now, what happens if we give too many arguments to {#syntax#}printf{#endsyntax#}?
- {#code_begin|test_err|Unused argument in "here is a string: '{s}' here is a number: {}#}
+ {#code_begin|test_err|Unused argument in 'here is a string: '{s}' here is a number: {}#}
const print = @import("std").debug.print;
const a_number: i32 = 1234;
@@ -8853,6 +8855,7 @@ pub fn main() void {
comptime {
const array: [5]u8 = "hello".*;
const garbage = array[5];
+ _ = garbage;
}
{#code_end#}
At runtime:
@@ -8873,6 +8876,7 @@ fn foo(x: []const u8) u8 {
comptime {
const value: i32 = -1;
const unsigned = @intCast(u32, value);
+ _ = unsigned;
}
{#code_end#}
At runtime:
@@ -8895,6 +8899,7 @@ pub fn main() void {
comptime {
const spartan_count: u16 = 300;
const byte = @intCast(u8, spartan_count);
+ _ = byte;
}
{#code_end#}
At runtime:
@@ -9028,6 +9033,7 @@ test "wraparound addition and subtraction" {
{#code_begin|test_err|operation caused overflow#}
comptime {
const x = @shlExact(@as(u8, 0b01010101), 2);
+ _ = x;
}
{#code_end#}
At runtime:
@@ -9046,6 +9052,7 @@ pub fn main() void {
{#code_begin|test_err|exact shift shifted out 1 bits#}
comptime {
const x = @shrExact(@as(u8, 0b10101010), 2);
+ _ = x;
}
{#code_end#}
At runtime:
@@ -9066,6 +9073,7 @@ comptime {
const a: i32 = 1;
const b: i32 = 0;
const c = a / b;
+ _ = c;
}
{#code_end#}
At runtime:
@@ -9087,6 +9095,7 @@ comptime {
const a: i32 = 10;
const b: i32 = 0;
const c = a % b;
+ _ = c;
}
{#code_end#}
At runtime:
@@ -9108,6 +9117,7 @@ comptime {
const a: u32 = 10;
const b: u32 = 3;
const c = @divExact(a, b);
+ _ = c;
}
{#code_end#}
At runtime:
@@ -9300,6 +9310,7 @@ fn foo(set1: Set1) void {
comptime {
const ptr = @intToPtr(*align(1) i32, 0x1);
const aligned = @alignCast(4, ptr);
+ _ = aligned;
}
{#code_end#}
At runtime:
@@ -9414,6 +9425,7 @@ fn bar(f: *Foo) void {
comptime {
const opt_ptr: ?*i32 = null;
const ptr = @ptrCast(*i32, opt_ptr);
+ _ = ptr;
}
{#code_end#}
At runtime: