mirror of
https://github.com/ziglang/zig.git
synced 2026-02-12 20:37:54 +00:00
Merge pull request #11530 from ziglang/test-harness
test: move compare and run tests to new test harness
This commit is contained in:
commit
3b8187072f
@ -45,7 +45,7 @@ cd $WORKSPACE
|
||||
|
||||
# Look for non-conforming code formatting.
|
||||
# Formatting errors can be fixed by running `zig fmt` on the files printed here.
|
||||
$ZIG fmt --check . --exclude test/compile_errors/
|
||||
$ZIG fmt --check . --exclude test/compile_errors/ --exclude test/incremental/
|
||||
|
||||
# Build stage2 standalone so that we can test stage2 against stage2 compiler-rt.
|
||||
$ZIG build -p stage2 -Dstatic-llvm -Dtarget=native-native-musl --search-prefix "$DEPS_LOCAL"
|
||||
|
||||
498
src/test.zig
498
src/test.zig
@ -34,42 +34,28 @@ test {
|
||||
var ctx = TestContext.init(std.testing.allocator, arena);
|
||||
defer ctx.deinit();
|
||||
|
||||
const compile_errors_dir_path = try std.fs.path.join(arena, &.{
|
||||
std.fs.path.dirname(@src().file).?, "..", "test", "compile_errors",
|
||||
});
|
||||
|
||||
var compile_errors_dir = try std.fs.cwd().openDir(compile_errors_dir_path, .{});
|
||||
defer compile_errors_dir.close();
|
||||
|
||||
{
|
||||
var stage2_dir = try compile_errors_dir.openDir("stage2", .{ .iterate = true });
|
||||
defer stage2_dir.close();
|
||||
const dir_path = try std.fs.path.join(arena, &.{
|
||||
std.fs.path.dirname(@src().file).?, "..", "test", "compile_errors",
|
||||
});
|
||||
|
||||
var dir = try std.fs.cwd().openDir(dir_path, .{ .iterate = true });
|
||||
defer dir.close();
|
||||
|
||||
// TODO make this incremental once the bug is solved that it triggers
|
||||
// See: https://github.com/ziglang/zig/issues/11344
|
||||
ctx.addErrorCasesFromDir("stage2", stage2_dir, .stage2, .Obj, false, .independent);
|
||||
ctx.addTestCasesFromDir(dir, .independent);
|
||||
}
|
||||
|
||||
if (!skip_stage1) {
|
||||
var stage1_dir = try compile_errors_dir.openDir("stage1", .{});
|
||||
defer stage1_dir.close();
|
||||
{
|
||||
const dir_path = try std.fs.path.join(arena, &.{
|
||||
std.fs.path.dirname(@src().file).?, "..", "test", "incremental",
|
||||
});
|
||||
|
||||
const Config = struct {
|
||||
name: []const u8,
|
||||
is_test: bool,
|
||||
output_mode: std.builtin.OutputMode,
|
||||
};
|
||||
var dir = try std.fs.cwd().openDir(dir_path, .{ .iterate = true });
|
||||
defer dir.close();
|
||||
|
||||
for ([_]Config{
|
||||
.{ .name = "obj", .is_test = false, .output_mode = .Obj },
|
||||
.{ .name = "exe", .is_test = false, .output_mode = .Exe },
|
||||
.{ .name = "test", .is_test = true, .output_mode = .Exe },
|
||||
}) |config| {
|
||||
var dir = try stage1_dir.openDir(config.name, .{ .iterate = true });
|
||||
defer dir.close();
|
||||
|
||||
ctx.addErrorCasesFromDir("stage1", dir, .stage1, config.output_mode, config.is_test, .independent);
|
||||
}
|
||||
ctx.addTestCasesFromDir(dir, .incremental);
|
||||
}
|
||||
|
||||
try @import("test_cases").addCases(&ctx);
|
||||
@ -154,6 +140,261 @@ const ErrorMsg = union(enum) {
|
||||
}
|
||||
};
|
||||
|
||||
/// Default config values for known test manifest key-value pairings.
|
||||
/// Currently handled defaults are:
|
||||
/// * backend
|
||||
/// * target
|
||||
/// * output_mode
|
||||
/// * is_test
|
||||
const TestManifestConfigDefaults = struct {
|
||||
/// Asserts if the key doesn't exist - yep, it's an oversight alright.
|
||||
fn get(@"type": TestManifest.Type, key: []const u8) []const u8 {
|
||||
if (std.mem.eql(u8, key, "backend")) {
|
||||
return "stage2";
|
||||
} else if (std.mem.eql(u8, key, "target")) {
|
||||
comptime {
|
||||
var defaults: []const u8 = "";
|
||||
// TODO should we only return "mainstream" targets by default here?
|
||||
// TODO we should also specify ABIs explicitly as the backends are
|
||||
// getting more and more complete
|
||||
// Linux
|
||||
inline for (&[_][]const u8{ "x86_64", "arm", "aarch64" }) |arch| {
|
||||
defaults = defaults ++ arch ++ "-linux" ++ ",";
|
||||
}
|
||||
// macOS
|
||||
inline for (&[_][]const u8{ "x86_64", "aarch64" }) |arch| {
|
||||
defaults = defaults ++ arch ++ "-macos" ++ ",";
|
||||
}
|
||||
// Wasm
|
||||
defaults = defaults ++ "wasm32-wasi";
|
||||
return defaults;
|
||||
}
|
||||
} else if (std.mem.eql(u8, key, "output_mode")) {
|
||||
return switch (@"type") {
|
||||
.@"error" => "Obj",
|
||||
.run => "Exe",
|
||||
.cli => @panic("TODO test harness for CLI tests"),
|
||||
};
|
||||
} else if (std.mem.eql(u8, key, "is_test")) {
|
||||
return "0";
|
||||
} else unreachable;
|
||||
}
|
||||
};
|
||||
|
||||
/// Manifest syntax example:
|
||||
/// (see https://github.com/ziglang/zig/issues/11288)
|
||||
///
|
||||
/// error
|
||||
/// backend=stage1,stage2
|
||||
/// output_mode=exe
|
||||
///
|
||||
/// :3:19: error: foo
|
||||
///
|
||||
/// run
|
||||
/// target=x86_64-linux,aarch64-macos
|
||||
///
|
||||
/// I am expected stdout! Hello!
|
||||
///
|
||||
/// cli
|
||||
///
|
||||
/// build test
|
||||
const TestManifest = struct {
|
||||
@"type": Type,
|
||||
config_map: std.StringHashMap([]const u8),
|
||||
trailing_bytes: []const u8 = "",
|
||||
|
||||
const Type = enum {
|
||||
@"error",
|
||||
run,
|
||||
cli,
|
||||
};
|
||||
|
||||
const TrailingIterator = struct {
|
||||
inner: std.mem.TokenIterator(u8),
|
||||
|
||||
fn next(self: *TrailingIterator) ?[]const u8 {
|
||||
const next_inner = self.inner.next() orelse return null;
|
||||
return std.mem.trim(u8, next_inner[2..], " \t");
|
||||
}
|
||||
};
|
||||
|
||||
fn ConfigValueIterator(comptime T: type) type {
|
||||
return struct {
|
||||
inner: std.mem.SplitIterator(u8),
|
||||
parse_fn: ParseFn(T),
|
||||
|
||||
fn next(self: *@This()) ?T {
|
||||
const next_raw = self.inner.next() orelse return null;
|
||||
return self.parse_fn(next_raw);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn parse(arena: Allocator, bytes: []const u8) !TestManifest {
|
||||
// The manifest is the last contiguous block of comments in the file
|
||||
// We scan for the beginning by searching backward for the first non-empty line that does not start with "//"
|
||||
var start: ?usize = null;
|
||||
var end: usize = bytes.len;
|
||||
if (bytes.len > 0) {
|
||||
var cursor: usize = bytes.len - 1;
|
||||
while (true) {
|
||||
// Move to beginning of line
|
||||
while (cursor > 0 and bytes[cursor - 1] != '\n') cursor -= 1;
|
||||
|
||||
if (std.mem.startsWith(u8, bytes[cursor..], "//")) {
|
||||
start = cursor; // Contiguous comment line, include in manifest
|
||||
} else {
|
||||
if (start != null) break; // Encountered non-comment line, end of manifest
|
||||
|
||||
// We ignore all-whitespace lines following the comment block, but anything else
|
||||
// means that there is no manifest present.
|
||||
if (std.mem.trim(u8, bytes[cursor..end], " \r\n\t").len == 0) {
|
||||
end = cursor;
|
||||
} else break; // If it's not whitespace, there is no manifest
|
||||
}
|
||||
|
||||
// Move to previous line
|
||||
if (cursor != 0) cursor -= 1 else break;
|
||||
}
|
||||
}
|
||||
|
||||
const actual_start = start orelse return error.MissingTestManifest;
|
||||
const manifest_bytes = bytes[actual_start..end];
|
||||
|
||||
var it = std.mem.tokenize(u8, manifest_bytes, "\r\n");
|
||||
|
||||
// First line is the test type
|
||||
const tt: Type = blk: {
|
||||
const line = it.next() orelse return error.MissingTestCaseType;
|
||||
const raw = std.mem.trim(u8, line[2..], " \t");
|
||||
if (std.mem.eql(u8, raw, "error")) {
|
||||
break :blk .@"error";
|
||||
} else if (std.mem.eql(u8, raw, "run")) {
|
||||
break :blk .run;
|
||||
} else if (std.mem.eql(u8, raw, "cli")) {
|
||||
break :blk .cli;
|
||||
} else {
|
||||
std.log.warn("unknown test case type requested: {s}", .{raw});
|
||||
return error.UnknownTestCaseType;
|
||||
}
|
||||
};
|
||||
|
||||
var manifest: TestManifest = .{
|
||||
.@"type" = tt,
|
||||
.config_map = std.StringHashMap([]const u8).init(arena),
|
||||
};
|
||||
|
||||
// Any subsequent line until a blank comment line is key=value(s) pair
|
||||
while (it.next()) |line| {
|
||||
const trimmed = std.mem.trim(u8, line[2..], " \t");
|
||||
if (trimmed.len == 0) break;
|
||||
|
||||
// Parse key=value(s)
|
||||
var kv_it = std.mem.split(u8, trimmed, "=");
|
||||
const key = kv_it.next() orelse return error.MissingKeyForConfig;
|
||||
try manifest.config_map.putNoClobber(key, kv_it.next() orelse return error.MissingValuesForConfig);
|
||||
}
|
||||
|
||||
// Finally, trailing is expected output
|
||||
manifest.trailing_bytes = manifest_bytes[it.index..];
|
||||
|
||||
return manifest;
|
||||
}
|
||||
|
||||
fn getConfigForKeyCustomParser(
|
||||
self: TestManifest,
|
||||
key: []const u8,
|
||||
comptime T: type,
|
||||
parse_fn: ParseFn(T),
|
||||
) ConfigValueIterator(T) {
|
||||
const bytes = self.config_map.get(key) orelse TestManifestConfigDefaults.get(self.@"type", key);
|
||||
return ConfigValueIterator(T){
|
||||
.inner = std.mem.split(u8, bytes, ","),
|
||||
.parse_fn = parse_fn,
|
||||
};
|
||||
}
|
||||
|
||||
fn getConfigForKey(
|
||||
self: TestManifest,
|
||||
key: []const u8,
|
||||
comptime T: type,
|
||||
) ConfigValueIterator(T) {
|
||||
return self.getConfigForKeyCustomParser(key, T, getDefaultParser(T));
|
||||
}
|
||||
|
||||
fn getConfigForKeyAlloc(
|
||||
self: TestManifest,
|
||||
allocator: Allocator,
|
||||
key: []const u8,
|
||||
comptime T: type,
|
||||
) error{OutOfMemory}![]const T {
|
||||
var out = std.ArrayList(T).init(allocator);
|
||||
defer out.deinit();
|
||||
var it = self.getConfigForKey(key, T);
|
||||
while (it.next()) |item| {
|
||||
try out.append(item);
|
||||
}
|
||||
return out.toOwnedSlice();
|
||||
}
|
||||
|
||||
fn getConfigForKeyAssertSingle(self: TestManifest, key: []const u8, comptime T: type) T {
|
||||
var it = self.getConfigForKey(key, T);
|
||||
const res = it.next().?;
|
||||
assert(it.next() == null);
|
||||
return res;
|
||||
}
|
||||
|
||||
fn trailing(self: TestManifest) TrailingIterator {
|
||||
return .{
|
||||
.inner = std.mem.tokenize(u8, self.trailing_bytes, "\r\n"),
|
||||
};
|
||||
}
|
||||
|
||||
fn trailingAlloc(self: TestManifest, allocator: Allocator) error{OutOfMemory}![]const []const u8 {
|
||||
var out = std.ArrayList([]const u8).init(allocator);
|
||||
defer out.deinit();
|
||||
var it = self.trailing();
|
||||
while (it.next()) |line| {
|
||||
try out.append(line);
|
||||
}
|
||||
return out.toOwnedSlice();
|
||||
}
|
||||
|
||||
fn ParseFn(comptime T: type) type {
|
||||
return fn ([]const u8) ?T;
|
||||
}
|
||||
|
||||
fn getDefaultParser(comptime T: type) ParseFn(T) {
|
||||
switch (@typeInfo(T)) {
|
||||
.Int => return struct {
|
||||
fn parse(str: []const u8) ?T {
|
||||
return std.fmt.parseInt(T, str, 0) catch null;
|
||||
}
|
||||
}.parse,
|
||||
.Bool => return struct {
|
||||
fn parse(str: []const u8) ?T {
|
||||
const as_int = std.fmt.parseInt(u1, str, 0) catch return null;
|
||||
return as_int > 0;
|
||||
}
|
||||
}.parse,
|
||||
.Enum => return struct {
|
||||
fn parse(str: []const u8) ?T {
|
||||
return std.meta.stringToEnum(T, str);
|
||||
}
|
||||
}.parse,
|
||||
.Struct => if (comptime std.mem.eql(u8, @typeName(T), "CrossTarget")) return struct {
|
||||
fn parse(str: []const u8) ?T {
|
||||
var opts = CrossTarget.ParseOptions{
|
||||
.arch_os_abi = str,
|
||||
};
|
||||
return CrossTarget.parse(opts) catch null;
|
||||
}
|
||||
}.parse else @compileError("no default parser for " ++ @typeName(T)),
|
||||
else => @compileError("no default parser for " ++ @typeName(T)),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
pub const TestContext = struct {
|
||||
arena: Allocator,
|
||||
cases: std.ArrayList(Case),
|
||||
@ -663,26 +904,15 @@ pub const TestContext = struct {
|
||||
incremental,
|
||||
};
|
||||
|
||||
/// Adds a compile-error test for each file in the provided directory, using the
|
||||
/// selected backend and output mode. If `one_test_case_per_file` is true, a new
|
||||
/// test case is created for each file. Otherwise, a single test case is used for
|
||||
/// all tests.
|
||||
/// Adds a test for each file in the provided directory, using the selected strategy.
|
||||
/// Recurses nested directories.
|
||||
///
|
||||
/// Each file should include a test manifest as a contiguous block of comments at
|
||||
/// the end of the file. The first line should be the test case name, followed by
|
||||
/// a blank line, then one expected errors on each line in the form
|
||||
/// `:line:column: error: message`
|
||||
pub fn addErrorCasesFromDir(
|
||||
ctx: *TestContext,
|
||||
name: []const u8,
|
||||
dir: std.fs.Dir,
|
||||
backend: Backend,
|
||||
output_mode: std.builtin.OutputMode,
|
||||
is_test: bool,
|
||||
strategy: Strategy,
|
||||
) void {
|
||||
/// the end of the file. The first line should be the test type, followed by a set of
|
||||
/// key-value config values, followed by a blank line, then the expected output.
|
||||
pub fn addTestCasesFromDir(ctx: *TestContext, dir: std.fs.Dir, strategy: Strategy) void {
|
||||
var current_file: []const u8 = "none";
|
||||
addErrorCasesFromDirInner(ctx, name, dir, backend, output_mode, is_test, strategy, ¤t_file) catch |err| {
|
||||
ctx.addTestCasesFromDirInner(dir, strategy, ¤t_file) catch |err| {
|
||||
std.debug.panic("test harness failed to process file '{s}': {s}\n", .{
|
||||
current_file, @errorName(err),
|
||||
});
|
||||
@ -749,33 +979,28 @@ pub const TestContext = struct {
|
||||
std.sort.sort([]const u8, filenames, Context{}, Context.lessThan);
|
||||
}
|
||||
|
||||
fn addErrorCasesFromDirInner(
|
||||
fn addTestCasesFromDirInner(
|
||||
ctx: *TestContext,
|
||||
name: []const u8,
|
||||
dir: std.fs.Dir,
|
||||
backend: Backend,
|
||||
output_mode: std.builtin.OutputMode,
|
||||
is_test: bool,
|
||||
strategy: Strategy,
|
||||
/// This is kept up to date with the currently being processed file so
|
||||
/// that if any errors occur the caller knows it happened during this file.
|
||||
current_file: *[]const u8,
|
||||
) !void {
|
||||
var opt_case: ?*Case = null;
|
||||
var cases = std.ArrayList(usize).init(ctx.arena);
|
||||
|
||||
var it = dir.iterate();
|
||||
var it = try dir.walk(ctx.arena);
|
||||
var filenames = std.ArrayList([]const u8).init(ctx.arena);
|
||||
defer filenames.deinit();
|
||||
|
||||
while (try it.next()) |entry| {
|
||||
if (entry.kind != .File) continue;
|
||||
|
||||
// Ignore stuff such as .swp files
|
||||
switch (Compilation.classifyFileExt(entry.name)) {
|
||||
switch (Compilation.classifyFileExt(entry.basename)) {
|
||||
.unknown => continue,
|
||||
else => {},
|
||||
}
|
||||
try filenames.append(try ctx.arena.dupe(u8, entry.name));
|
||||
try filenames.append(try ctx.arena.dupe(u8, entry.path));
|
||||
}
|
||||
|
||||
// Sort filenames, so that incremental tests are contiguous and in-order
|
||||
@ -785,108 +1010,99 @@ pub const TestContext = struct {
|
||||
for (filenames.items) |filename| {
|
||||
current_file.* = filename;
|
||||
|
||||
{ // First, check if this file is part of an incremental update sequence
|
||||
// First, check if this file is part of an incremental update sequence
|
||||
// Split filename into "<base_name>.<index>.<file_ext>"
|
||||
const prev_parts = getTestFileNameParts(prev_filename);
|
||||
const new_parts = getTestFileNameParts(filename);
|
||||
|
||||
// Split filename into "<base_name>.<index>.<file_ext>"
|
||||
const prev_parts = getTestFileNameParts(prev_filename);
|
||||
const new_parts = getTestFileNameParts(filename);
|
||||
|
||||
// If base_name and file_ext match, these files are in the same test sequence
|
||||
// and the new one should be the incremented version of the previous test
|
||||
if (std.mem.eql(u8, prev_parts.base_name, new_parts.base_name) and
|
||||
std.mem.eql(u8, prev_parts.file_ext, new_parts.file_ext))
|
||||
{
|
||||
|
||||
// This is "foo.X.zig" followed by "foo.Y.zig". Make sure that X = Y + 1
|
||||
if (prev_parts.test_index == null) return error.InvalidIncrementalTestIndex;
|
||||
if (new_parts.test_index == null) return error.InvalidIncrementalTestIndex;
|
||||
if (new_parts.test_index.? != prev_parts.test_index.? + 1) return error.InvalidIncrementalTestIndex;
|
||||
} else {
|
||||
|
||||
// This is not the same test sequence, so the new file must be the first file
|
||||
// in a new sequence ("*.0.zig") or an independent test file ("*.zig")
|
||||
if (new_parts.test_index != null and new_parts.test_index.? != 0) return error.InvalidIncrementalTestIndex;
|
||||
|
||||
if (strategy == .independent)
|
||||
opt_case = null; // Generate a new independent test case for this update
|
||||
}
|
||||
// If base_name and file_ext match, these files are in the same test sequence
|
||||
// and the new one should be the incremented version of the previous test
|
||||
if (std.mem.eql(u8, prev_parts.base_name, new_parts.base_name) and
|
||||
std.mem.eql(u8, prev_parts.file_ext, new_parts.file_ext))
|
||||
{
|
||||
// This is "foo.X.zig" followed by "foo.Y.zig". Make sure that X = Y + 1
|
||||
if (prev_parts.test_index == null) return error.InvalidIncrementalTestIndex;
|
||||
if (new_parts.test_index == null) return error.InvalidIncrementalTestIndex;
|
||||
if (new_parts.test_index.? != prev_parts.test_index.? + 1) return error.InvalidIncrementalTestIndex;
|
||||
} else {
|
||||
// This is not the same test sequence, so the new file must be the first file
|
||||
// in a new sequence ("*.0.zig") or an independent test file ("*.zig")
|
||||
if (new_parts.test_index != null and new_parts.test_index.? != 0) return error.InvalidIncrementalTestIndex;
|
||||
cases.clearRetainingCapacity();
|
||||
}
|
||||
prev_filename = filename;
|
||||
|
||||
const max_file_size = 10 * 1024 * 1024;
|
||||
const src = try dir.readFileAllocOptions(ctx.arena, filename, max_file_size, null, 1, 0);
|
||||
|
||||
// The manifest is the last contiguous block of comments in the file
|
||||
// We scan for the beginning by searching backward for the first non-empty line that does not start with "//"
|
||||
var manifest_start: ?usize = null;
|
||||
var manifest_end: usize = src.len;
|
||||
if (src.len > 0) {
|
||||
var cursor: usize = src.len - 1;
|
||||
while (true) {
|
||||
// Move to beginning of line
|
||||
while (cursor > 0 and src[cursor - 1] != '\n') cursor -= 1;
|
||||
// Parse the manifest
|
||||
var manifest = try TestManifest.parse(ctx.arena, src);
|
||||
|
||||
if (std.mem.startsWith(u8, src[cursor..], "//")) {
|
||||
manifest_start = cursor; // Contiguous comment line, include in manifest
|
||||
} else {
|
||||
if (manifest_start != null) break; // Encountered non-comment line, end of manifest
|
||||
if (cases.items.len == 0) {
|
||||
const backends = try manifest.getConfigForKeyAlloc(ctx.arena, "backend", Backend);
|
||||
const targets = try manifest.getConfigForKeyAlloc(ctx.arena, "target", CrossTarget);
|
||||
const is_test = manifest.getConfigForKeyAssertSingle("is_test", bool);
|
||||
const output_mode = manifest.getConfigForKeyAssertSingle("output_mode", std.builtin.OutputMode);
|
||||
|
||||
// We ignore all-whitespace lines following the comment block, but anything else
|
||||
// means that there is no manifest present.
|
||||
if (std.mem.trim(u8, src[cursor..manifest_end], " \r\n\t").len == 0) {
|
||||
manifest_end = cursor;
|
||||
} else break; // If it's not whitespace, there is no manifest
|
||||
const name_prefix = blk: {
|
||||
const ext_index = std.mem.lastIndexOfScalar(u8, current_file.*, '.') orelse
|
||||
return error.InvalidFilename;
|
||||
const index = std.mem.lastIndexOfScalar(u8, current_file.*[0..ext_index], '.') orelse ext_index;
|
||||
break :blk current_file.*[0..index];
|
||||
};
|
||||
|
||||
// Cross-product to get all possible test combinations
|
||||
for (backends) |backend| {
|
||||
for (targets) |target| {
|
||||
const name = try std.fmt.allocPrint(ctx.arena, "{s} ({s}, {s})", .{
|
||||
name_prefix,
|
||||
@tagName(backend),
|
||||
try target.zigTriple(ctx.arena),
|
||||
});
|
||||
const next = ctx.cases.items.len;
|
||||
try ctx.cases.append(.{
|
||||
.name = name,
|
||||
.target = target,
|
||||
.backend = backend,
|
||||
.updates = std.ArrayList(TestContext.Update).init(ctx.cases.allocator),
|
||||
.is_test = is_test,
|
||||
.output_mode = output_mode,
|
||||
.link_libc = backend == .llvm,
|
||||
.files = std.ArrayList(TestContext.File).init(ctx.cases.allocator),
|
||||
});
|
||||
try cases.append(next);
|
||||
}
|
||||
|
||||
// Move to previous line
|
||||
if (cursor != 0) cursor -= 1 else break;
|
||||
}
|
||||
}
|
||||
|
||||
var errors = std.ArrayList([]const u8).init(ctx.arena);
|
||||
|
||||
if (manifest_start) |start| {
|
||||
// Due to the above processing, we know that this is a contiguous block of comments
|
||||
// and do not need to re-validate the leading "//" on each line
|
||||
var manifest_it = std.mem.tokenize(u8, src[start..manifest_end], "\r\n");
|
||||
|
||||
// First line is the test case name
|
||||
const first_line = manifest_it.next() orelse return error.MissingTestCaseName;
|
||||
const case_name = try std.mem.concat(ctx.arena, u8, &.{ name, ": ", std.mem.trim(u8, first_line[2..], " \t") });
|
||||
|
||||
// If the second line is present, it should be blank
|
||||
if (manifest_it.next()) |second_line| {
|
||||
if (std.mem.trim(u8, second_line[2..], " \t").len != 0) return error.SecondLineNotBlank;
|
||||
}
|
||||
|
||||
// All following lines are expected error messages
|
||||
while (manifest_it.next()) |line| try errors.append(try ctx.arena.dupe(u8, std.mem.trim(u8, line[2..], " \t")));
|
||||
|
||||
const case = opt_case orelse case: {
|
||||
ctx.cases.append(TestContext.Case{
|
||||
.name = name,
|
||||
.target = .{},
|
||||
.backend = backend,
|
||||
.updates = std.ArrayList(TestContext.Update).init(ctx.cases.allocator),
|
||||
.is_test = is_test,
|
||||
.output_mode = output_mode,
|
||||
.files = std.ArrayList(TestContext.File).init(ctx.cases.allocator),
|
||||
}) catch @panic("out of memory");
|
||||
const case = &ctx.cases.items[ctx.cases.items.len - 1];
|
||||
opt_case = case;
|
||||
break :case case;
|
||||
};
|
||||
switch (strategy) {
|
||||
.independent => {
|
||||
case.name = case_name;
|
||||
case.addError(src, errors.items);
|
||||
for (cases.items) |case_index| {
|
||||
const case = &ctx.cases.items[case_index];
|
||||
switch (manifest.@"type") {
|
||||
.@"error" => {
|
||||
const errors = try manifest.trailingAlloc(ctx.arena);
|
||||
switch (strategy) {
|
||||
.independent => {
|
||||
case.addError(src, errors);
|
||||
},
|
||||
.incremental => {
|
||||
case.addErrorNamed("update", src, errors);
|
||||
},
|
||||
}
|
||||
},
|
||||
.incremental => {
|
||||
case.addErrorNamed(case_name, src, errors.items);
|
||||
.run => {
|
||||
var output = std.ArrayList(u8).init(ctx.arena);
|
||||
var trailing_it = manifest.trailing();
|
||||
while (trailing_it.next()) |line| {
|
||||
try output.appendSlice(line);
|
||||
try output.append('\n');
|
||||
}
|
||||
if (output.items.len > 0) {
|
||||
try output.resize(output.items.len - 1);
|
||||
}
|
||||
case.addCompareOutput(src, output.toOwnedSlice());
|
||||
},
|
||||
.cli => @panic("TODO cli tests"),
|
||||
}
|
||||
} else {
|
||||
return error.MissingManifest;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,8 +69,10 @@ test {
|
||||
_ = @import("behavior/bugs/7003.zig");
|
||||
_ = @import("behavior/bugs/7027.zig");
|
||||
_ = @import("behavior/bugs/7047.zig");
|
||||
_ = @import("behavior/bugs/7187.zig");
|
||||
_ = @import("behavior/bugs/7250.zig");
|
||||
_ = @import("behavior/bugs/9584.zig");
|
||||
_ = @import("behavior/bugs/10138.zig");
|
||||
_ = @import("behavior/bugs/10147.zig");
|
||||
_ = @import("behavior/bugs/10970.zig");
|
||||
_ = @import("behavior/bugs/11046.zig");
|
||||
|
||||
34
test/behavior/bugs/10138.zig
Normal file
34
test/behavior/bugs/10138.zig
Normal file
@ -0,0 +1,34 @@
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
|
||||
test "registers get overwritten when ignoring return" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
if (builtin.cpu.arch != .x86_64 or builtin.os.tag != .linux) return error.SkipZigTest;
|
||||
|
||||
const fd = open();
|
||||
_ = write(fd, "a", 1);
|
||||
_ = close(fd);
|
||||
}
|
||||
|
||||
fn open() usize {
|
||||
return 42;
|
||||
}
|
||||
|
||||
fn write(fd: usize, a: [*]const u8, len: usize) usize {
|
||||
return syscall4(.WRITE, fd, @ptrToInt(a), len);
|
||||
}
|
||||
|
||||
fn syscall4(n: enum { WRITE }, a: usize, b: usize, c: usize) usize {
|
||||
_ = n;
|
||||
_ = a;
|
||||
_ = b;
|
||||
_ = c;
|
||||
return 23;
|
||||
}
|
||||
|
||||
fn close(fd: usize) usize {
|
||||
if (fd != 42)
|
||||
unreachable;
|
||||
return 0;
|
||||
}
|
||||
18
test/behavior/bugs/7187.zig
Normal file
18
test/behavior/bugs/7187.zig
Normal file
@ -0,0 +1,18 @@
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const expect = std.testing.expect;
|
||||
|
||||
test "miscompilation with bool return type" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
|
||||
var x: usize = 1;
|
||||
var y: bool = getFalse();
|
||||
_ = y;
|
||||
|
||||
try expect(x == 1);
|
||||
}
|
||||
|
||||
fn getFalse() bool {
|
||||
return false;
|
||||
}
|
||||
@ -1,22 +1,9 @@
|
||||
const std = @import("std");
|
||||
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
|
||||
// a set of targets that all test cases run on unless specifically overridden. For now, each test
|
||||
// case applies to only the specified target.
|
||||
|
||||
pub fn addCases(ctx: *TestContext) !void {
|
||||
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/riscv64.zig").addCases(ctx);
|
||||
try @import("stage2/plan9.zig").addCases(ctx);
|
||||
try @import("stage2/x86_64.zig").addCases(ctx);
|
||||
try @import("stage2/sparcv9.zig").addCases(ctx);
|
||||
// https://github.com/ziglang/zig/issues/10968
|
||||
//try @import("stage2/nvptx.zig").addCases(ctx);
|
||||
}
|
||||
|
||||
@ -3,207 +3,6 @@ const builtin = @import("builtin");
|
||||
const TestContext = @import("../src/test.zig").TestContext;
|
||||
|
||||
pub fn addCases(ctx: *TestContext) !void {
|
||||
{
|
||||
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",
|
||||
});
|
||||
}
|
||||
{
|
||||
var case = ctx.obj("callconv(.Signal) on unsupported platform", .{
|
||||
.cpu_arch = .x86_64,
|
||||
.os_tag = .linux,
|
||||
.abi = .none,
|
||||
});
|
||||
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",
|
||||
});
|
||||
}
|
||||
{
|
||||
const case = ctx.obj("callconv(.Stdcall, .Fastcall, .Thiscall) on unsupported platform", .{
|
||||
.cpu_arch = .x86_64,
|
||||
.os_tag = .linux,
|
||||
.abi = .none,
|
||||
});
|
||||
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; _ = 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",
|
||||
});
|
||||
}
|
||||
{
|
||||
const case = ctx.obj("callconv(.Stdcall, .Fastcall, .Thiscall) on unsupported platform", .{
|
||||
.cpu_arch = .x86_64,
|
||||
.os_tag = .linux,
|
||||
.abi = .none,
|
||||
});
|
||||
case.backend = .stage1;
|
||||
case.addError(
|
||||
\\export fn entry1() callconv(.Stdcall) void {}
|
||||
\\export fn entry2() callconv(.Fastcall) void {}
|
||||
\\export fn entry3() callconv(.Thiscall) void {}
|
||||
, &[_][]const u8{
|
||||
"tmp.zig:1:29: error: callconv 'Stdcall' is only available on x86, not x86_64",
|
||||
"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",
|
||||
});
|
||||
}
|
||||
{
|
||||
const case = ctx.obj("callconv(.Vectorcall) on unsupported platform", .{
|
||||
.cpu_arch = .x86_64,
|
||||
.os_tag = .linux,
|
||||
.abi = .none,
|
||||
});
|
||||
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",
|
||||
});
|
||||
}
|
||||
{
|
||||
const case = ctx.obj("callconv(.APCS, .AAPCS, .AAPCSVFP) on unsupported platform", .{
|
||||
.cpu_arch = .x86_64,
|
||||
.os_tag = .linux,
|
||||
.abi = .none,
|
||||
});
|
||||
case.backend = .stage1;
|
||||
case.addError(
|
||||
\\export fn entry1() callconv(.APCS) void {}
|
||||
\\export fn entry2() callconv(.AAPCS) void {}
|
||||
\\export fn entry3() callconv(.AAPCSVFP) void {}
|
||||
, &[_][]const u8{
|
||||
"tmp.zig:1:29: error: callconv 'APCS' is only available on ARM, not x86_64",
|
||||
"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",
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
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, .{});
|
||||
\\}
|
||||
\\fn foo() void {}
|
||||
, &[_][]const u8{
|
||||
"tmp.zig:3:5: error: target arch 'wasm32' does not support calling with a new stack",
|
||||
});
|
||||
}
|
||||
|
||||
// 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.
|
||||
ctx.objErrStage1("incompatible sentinels",
|
||||
\\export fn entry1(ptr: [*:255]u8) [*:0]u8 {
|
||||
\\ return ptr;
|
||||
\\}
|
||||
\\export fn entry2(ptr: [*]u8) [*:0]u8 {
|
||||
\\ return ptr;
|
||||
\\}
|
||||
\\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'",
|
||||
"tmp.zig:2:12: note: destination pointer requires a terminating '0' sentinel, but source pointer has a terminating '255' sentinel",
|
||||
"tmp.zig:5:12: error: expected type '[*:0]u8', found '[*]u8'",
|
||||
"tmp.zig:5:12: note: destination pointer requires a terminating '0' sentinel",
|
||||
|
||||
"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:12:31: error: expected type '[2:0]u8', found '[2]u8'",
|
||||
"tmp.zig:12:31: note: destination array requires a terminating '0' sentinel",
|
||||
});
|
||||
|
||||
{
|
||||
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",
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
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'",
|
||||
});
|
||||
}
|
||||
|
||||
if (builtin.os.tag == .linux) {
|
||||
ctx.testErrStage1("implicit dependency on libc",
|
||||
\\extern "c" fn exit(u8) void;
|
||||
\\export fn entry() void {
|
||||
\\ exit(0);
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
"tmp.zig:3:5: error: dependency on libc must be explicitly specified in the build command",
|
||||
});
|
||||
|
||||
ctx.testErrStage1("libc headers note",
|
||||
\\const c = @cImport(@cInclude("stdio.h"));
|
||||
\\export fn entry() void {
|
||||
\\ _ = c.printf("hello, world!\n");
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
"tmp.zig:1:11: error: C import failed",
|
||||
"tmp.zig:1:11: note: libc headers not available; compilation does not link against libc",
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
const case = ctx.obj("wrong same named struct", .{});
|
||||
case.backend = .stage1;
|
||||
@ -366,21 +165,4 @@ pub fn addCases(ctx: *TestContext) !void {
|
||||
//, &[_][]const u8{
|
||||
// "tmp.zig:4:1: error: unable to inline function",
|
||||
//});
|
||||
|
||||
{
|
||||
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",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
pub fn (main) void {}
|
||||
|
||||
// main missing name
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
// output_mode=Exe
|
||||
//
|
||||
// tmp.zig:1:5: error: missing function name
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
|
||||
|
||||
// missing main fn in executable
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
// output_mode=Exe
|
||||
//
|
||||
// error: root source file has no member called 'main'
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
fn main() void {}
|
||||
|
||||
// private main fn
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
// output_mode=Exe
|
||||
//
|
||||
// error: 'main' is private
|
||||
// tmp.zig:1:1: note: declared here
|
||||
|
||||
@ -5,6 +5,8 @@ export fn a() void {
|
||||
_ = t;
|
||||
}
|
||||
|
||||
// C pointer pointing to non C ABI compatible type or has align attr
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:3:19: error: C pointers cannot point to non-C-ABI-compatible type 'Foo'
|
||||
|
||||
@ -4,6 +4,8 @@ export fn a() void {
|
||||
_ = y;
|
||||
}
|
||||
|
||||
// C pointer to anyopaque
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:3:16: error: C pointers cannot point to opaque types
|
||||
|
||||
@ -7,6 +7,8 @@ fn func(comptime T: type) void {
|
||||
_ = x;
|
||||
}
|
||||
|
||||
// @Frame() of generic function
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:2:16: error: @Frame() of generic function
|
||||
|
||||
@ -8,7 +8,9 @@ export fn f2(x: V(4, u32)) V(4, u32) {
|
||||
return -y;
|
||||
}
|
||||
|
||||
// Issue #5586: Make unary minus for unsigned types a compile error
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:3:12: error: negation of type 'u32'
|
||||
// tmp.zig:8:12: error: negation of type 'u32'
|
||||
|
||||
@ -3,6 +3,8 @@ fn foo() void {
|
||||
_ = sequence;
|
||||
}
|
||||
|
||||
// Issue #6823: don't allow .* to be followed by **
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:2:28: error: '.*' cannot be followed by '*'. Are you missing a space?
|
||||
|
||||
@ -9,6 +9,8 @@ pub fn main() !void {
|
||||
}
|
||||
}
|
||||
|
||||
// Issue #9165: windows tcp server compilation error
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// error: Unsupported OS
|
||||
|
||||
@ -4,6 +4,8 @@ comptime {
|
||||
_ = z;
|
||||
}
|
||||
|
||||
// access non-existent member of error set
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:3:18: error: no error named 'Bar' in 'Foo'
|
||||
|
||||
@ -12,7 +12,9 @@ export fn entry() void {
|
||||
_ = x;
|
||||
}
|
||||
|
||||
// accessing runtime parameter from outer function
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:4:24: error: 'y' not accessible from inner function
|
||||
// tmp.zig:3:28: note: crossed function definition here
|
||||
|
||||
@ -3,6 +3,8 @@ comptime {
|
||||
a += a;
|
||||
}
|
||||
|
||||
// add assign on undefined value
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:3:5: error: use of undefined value here causes undefined behavior
|
||||
|
||||
@ -3,6 +3,8 @@ comptime {
|
||||
_ = a + a;
|
||||
}
|
||||
|
||||
// add on undefined value
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:3:9: error: use of undefined value here causes undefined behavior
|
||||
|
||||
@ -5,6 +5,8 @@ fn add(a: u16, b: u16) u16 {
|
||||
|
||||
export fn entry() usize { return @sizeOf(@TypeOf(y)); }
|
||||
|
||||
// add overflow in function evaluation
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:3:14: error: operation caused overflow
|
||||
|
||||
@ -3,6 +3,8 @@ comptime {
|
||||
a +%= a;
|
||||
}
|
||||
|
||||
// add wrap assign on undefined value
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:3:5: error: use of undefined value here causes undefined behavior
|
||||
|
||||
@ -3,6 +3,8 @@ comptime {
|
||||
_ = a +% a;
|
||||
}
|
||||
|
||||
// add wrap on undefined value
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:3:9: error: use of undefined value here causes undefined behavior
|
||||
|
||||
@ -5,6 +5,8 @@ const x = Foo {.field = 1} + Foo {.field = 2};
|
||||
|
||||
export fn entry() usize { return @sizeOf(@TypeOf(x)); }
|
||||
|
||||
// addition with non numbers
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:4:28: error: invalid operands to binary expression: 'Foo' and 'Foo'
|
||||
|
||||
@ -3,6 +3,8 @@ const y = &x;
|
||||
fn foo() *const i32 { return y; }
|
||||
export fn entry() usize { return @sizeOf(@TypeOf(foo)); }
|
||||
|
||||
// address of number literal
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:3:30: error: expected type '*const i32', found '*const comptime_int'
|
||||
|
||||
@ -2,6 +2,8 @@ export fn entry() void {
|
||||
@alignCast(4, @as(u32, 3));
|
||||
}
|
||||
|
||||
// @alignCast expects pointer or slice
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:2:19: error: expected pointer or slice, found 'u32'
|
||||
|
||||
@ -0,0 +1,9 @@
|
||||
export fn foo() align(1) void {
|
||||
return;
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=wasm32-freestanding-none
|
||||
//
|
||||
// tmp.zig:1:23: error: align(N) expr is not allowed on function prototypes in wasm32/wasm64
|
||||
@ -3,6 +3,8 @@ export fn f() void {
|
||||
_ = s;
|
||||
}
|
||||
|
||||
// aligned variable of zero-bit type
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:2:5: error: variable 's' of zero-bit type 'struct:2:12' has no in-memory representation, it cannot be aligned
|
||||
|
||||
@ -7,6 +7,8 @@ export fn entry1() void {
|
||||
_ = x;
|
||||
}
|
||||
|
||||
// alignment of enum field specified
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:3:7: error: expected ',' after field
|
||||
|
||||
@ -12,7 +12,9 @@ export fn entry() void {
|
||||
bar();
|
||||
}
|
||||
|
||||
// ambiguous decl reference
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:5:13: error: ambiguous reference
|
||||
// tmp.zig:7:9: note: declared here
|
||||
|
||||
@ -3,6 +3,8 @@ comptime {
|
||||
_ = a and a;
|
||||
}
|
||||
|
||||
// and on undefined value
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:3:9: error: use of undefined value here causes undefined behavior
|
||||
|
||||
@ -7,7 +7,9 @@ export fn g() void {
|
||||
_ = bad[0];
|
||||
}
|
||||
|
||||
// array access of non array
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:3:8: error: array access of non-array type 'bool'
|
||||
// tmp.zig:7:12: error: array access of non-array type 'bool'
|
||||
|
||||
@ -3,6 +3,8 @@ export fn foo() void {
|
||||
_ = b;
|
||||
}
|
||||
|
||||
// array access of type
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:2:14: error: array access of non-array type 'type'
|
||||
|
||||
@ -2,6 +2,8 @@ export fn f() void {
|
||||
i[i] = i[i];
|
||||
}
|
||||
|
||||
// array access of undeclared identifier
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:2:5: error: use of undeclared identifier 'i'
|
||||
|
||||
@ -9,7 +9,9 @@ export fn g() void {
|
||||
_ = array[bad];
|
||||
}
|
||||
|
||||
// array access with non integer index
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:4:11: error: expected type 'usize', found 'bool'
|
||||
// tmp.zig:9:15: error: expected type 'usize', found 'bool'
|
||||
|
||||
@ -4,6 +4,8 @@ const a = derp ++ "foo";
|
||||
|
||||
export fn entry() usize { return @sizeOf(@TypeOf(a)); }
|
||||
|
||||
// array concatenation with wrong type
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:3:11: error: expected array, found 'usize'
|
||||
|
||||
@ -6,7 +6,9 @@ export fn zig_return_array() [10]u8 {
|
||||
return "1234567890".*;
|
||||
}
|
||||
|
||||
// array in c exported function
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:1:24: error: parameter of type '[10]u8' not allowed in function with calling convention 'C'
|
||||
// tmp.zig:5:30: error: return type '[10]u8' not allowed in function with calling convention 'C'
|
||||
|
||||
@ -10,6 +10,8 @@ fn doSomeAsm() void {
|
||||
);
|
||||
}
|
||||
|
||||
// asm at compile time
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:6:5: error: unable to evaluate constant expression
|
||||
|
||||
@ -4,7 +4,9 @@ export fn entry() void {
|
||||
}
|
||||
fn b() callconv(.Inline) void { }
|
||||
|
||||
// assign inline fn to non-comptime var
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:2:5: error: functions marked inline must be stored in const or comptime var
|
||||
// tmp.zig:5:1: note: declared here
|
||||
|
||||
@ -2,6 +2,8 @@ const a: *u8 = null;
|
||||
|
||||
export fn entry() usize { return @sizeOf(@TypeOf(a)); }
|
||||
|
||||
// assign null to non-optional pointer
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:1:16: error: expected type '*u8', found '@Type(.Null)'
|
||||
|
||||
@ -3,6 +3,8 @@ export fn f() void {
|
||||
cstr[0] = 'W';
|
||||
}
|
||||
|
||||
// assign through constant pointer
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:3:13: error: cannot assign to constant
|
||||
|
||||
@ -3,6 +3,8 @@ export fn f() void {
|
||||
cstr[0] = 'W';
|
||||
}
|
||||
|
||||
// assign through constant slice
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:3:13: error: cannot assign to constant
|
||||
|
||||
@ -6,6 +6,8 @@ export fn derp() void {
|
||||
f.field = 0;
|
||||
}
|
||||
|
||||
// assign to constant field
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:6:15: error: cannot assign to constant
|
||||
|
||||
@ -3,6 +3,8 @@ export fn f() void {
|
||||
a = 4;
|
||||
}
|
||||
|
||||
// assign to constant variable
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:3:9: error: cannot assign to constant
|
||||
|
||||
@ -2,6 +2,8 @@ export fn entry() void {
|
||||
'a'.* = 1;
|
||||
}
|
||||
|
||||
// assign to invalid dereference
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:2:8: error: attempt to dereference non-pointer type 'comptime_int'
|
||||
|
||||
@ -3,6 +3,8 @@ export fn foo() void {
|
||||
_ = vga_mem;
|
||||
}
|
||||
|
||||
// assign too big number to u16
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:2:24: error: integer value 753664 cannot be coerced to type 'u16'
|
||||
|
||||
@ -2,7 +2,9 @@ export fn f() void {
|
||||
const a = return;
|
||||
}
|
||||
|
||||
// assign unreachable
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:2:5: error: unreachable code
|
||||
// tmp.zig:2:15: note: control flow is diverted here
|
||||
|
||||
@ -14,6 +14,8 @@ export fn entry() void {
|
||||
_ = s;
|
||||
}
|
||||
|
||||
// assigning to struct or union fields that are not optionals with a function that returns an optional
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:11:27: error: cannot convert optional to payload type. consider using `.?`, `orelse`, or `if`. expected type 'u8', found '?u8'
|
||||
|
||||
@ -6,6 +6,8 @@ fn amain() callconv(.Async) void {
|
||||
_ = x;
|
||||
}
|
||||
|
||||
// async function depends on its own frame
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:4:1: error: cannot resolve '@Frame(amain)': function not fully analyzed yet
|
||||
|
||||
@ -9,7 +9,9 @@ fn other() void {
|
||||
_ = x;
|
||||
}
|
||||
|
||||
// async function indirectly depends on its own frame
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:4:1: error: unable to determine async function frame of 'amain'
|
||||
// tmp.zig:5:10: note: analysis of function 'other' depends on the frame
|
||||
|
||||
@ -3,6 +3,8 @@ export fn entry() void {
|
||||
@atomicStore(u32, &x, 1, .Acquire);
|
||||
}
|
||||
|
||||
// atomic orderings of atomicStore Acquire or AcqRel
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:3:30: error: @atomicStore atomic ordering must not be Acquire or AcqRel
|
||||
|
||||
@ -4,6 +4,8 @@ export fn f() void {
|
||||
while (!@cmpxchgWeak(i32, &x, 1234, 5678, AtomicOrder.Monotonic, AtomicOrder.SeqCst)) {}
|
||||
}
|
||||
|
||||
// atomic orderings of cmpxchg - failure stricter than success
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:4:81: error: failure atomic ordering must be no stricter than success
|
||||
|
||||
@ -4,6 +4,8 @@ export fn f() void {
|
||||
while (!@cmpxchgWeak(i32, &x, 1234, 5678, AtomicOrder.Unordered, AtomicOrder.Unordered)) {}
|
||||
}
|
||||
|
||||
// atomic orderings of cmpxchg - success Monotonic or stricter
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:4:58: error: success atomic ordering must be Monotonic or stricter
|
||||
|
||||
@ -2,6 +2,8 @@ export fn entry() void {
|
||||
@fence(.Monotonic);
|
||||
}
|
||||
|
||||
// atomic orderings of fence Acquire or stricter
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:2:12: error: atomic ordering must be Acquire or stricter
|
||||
|
||||
@ -3,6 +3,8 @@ export fn entry() void {
|
||||
_ = @atomicRmw(bool, &x, .Add, true, .SeqCst);
|
||||
}
|
||||
|
||||
// atomicrmw with bool op not .Xchg
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:3:30: error: @atomicRmw with bool only allowed with .Xchg
|
||||
|
||||
@ -9,6 +9,8 @@ export fn entry() void {
|
||||
_ = @atomicRmw(E, &x, .Add, .b, .SeqCst);
|
||||
}
|
||||
|
||||
// atomicrmw with enum op not .Xchg
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:9:27: error: @atomicRmw with enum only allowed with .Xchg
|
||||
|
||||
@ -3,6 +3,8 @@ export fn entry() void {
|
||||
_ = @atomicRmw(f32, &x, .And, 2, .SeqCst);
|
||||
}
|
||||
|
||||
// atomicrmw with float op not .Xchg, .Add or .Sub
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:3:29: error: @atomicRmw with float only allowed with .Xchg, .Add and .Sub
|
||||
|
||||
@ -4,6 +4,8 @@ export fn entry() void {
|
||||
}
|
||||
}
|
||||
|
||||
// attempt to cast enum literal to error
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:3:9: error: expected type 'error{Hi}', found '@Type(.EnumLiteral)'
|
||||
|
||||
@ -5,7 +5,9 @@ fn SimpleList(comptime L: usize) type {
|
||||
};
|
||||
}
|
||||
|
||||
// attempt to close over comptime variable from outer scope
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:4:19: error: mutable 'T' not accessible from here
|
||||
// tmp.zig:2:9: note: declared mutable here
|
||||
|
||||
@ -3,6 +3,8 @@ comptime {
|
||||
_ = @Type(.{ .Float = .{ .bits = 17 } });
|
||||
}
|
||||
|
||||
// attempt to create 17 bit float type
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:3:16: error: 17-bit float unsupported
|
||||
|
||||
@ -7,6 +7,8 @@ export fn entry() void {
|
||||
_ = x;
|
||||
}
|
||||
|
||||
// attempt to negate a non-integer, non-float or non-vector type
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:6:15: error: negation of type 'anyerror!u32'
|
||||
|
||||
@ -9,7 +9,9 @@ export fn entry2() void {
|
||||
bar(&{});
|
||||
}
|
||||
|
||||
// attempt to use 0 bit type in extern fn
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:1:23: error: parameter of type '*void' has 0 bits; not allowed in function with calling convention 'C'
|
||||
// tmp.zig:7:11: error: parameter of type '*void' has 0 bits; not allowed in function with calling convention 'C'
|
||||
|
||||
@ -5,6 +5,8 @@ export fn entry(a: bool, b: bool) i32 {
|
||||
return 5678;
|
||||
}
|
||||
|
||||
// attempted `&&`
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:2:11: error: ambiguous use of '&&'; use 'and' for logical AND, or change whitespace to ' & &' for bitwise AND
|
||||
|
||||
@ -5,7 +5,9 @@ export fn entry(a: bool, b: bool) i32 {
|
||||
return 5678;
|
||||
}
|
||||
|
||||
// attempted `||` on boolean values
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:2:9: error: expected error set type, found 'bool'
|
||||
// tmp.zig:2:11: note: `||` merges error sets; `or` performs boolean OR
|
||||
|
||||
@ -3,6 +3,8 @@ export fn entry() void {
|
||||
_ = x;
|
||||
}
|
||||
|
||||
// attempted implicit cast from T to [*]const T
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:2:30: error: expected type '[*]const bool', found 'bool'
|
||||
|
||||
@ -6,7 +6,9 @@ export fn entry(byte: u8) void {
|
||||
_ = byte;
|
||||
}
|
||||
|
||||
// attempted implicit cast from *const T to *[1]T
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:4:22: error: expected type '*[1]i32', found '*const i32'
|
||||
// tmp.zig:4:22: note: cast discards const qualifier
|
||||
|
||||
@ -4,6 +4,8 @@ export fn entry() void {
|
||||
_ = x;
|
||||
}
|
||||
|
||||
// attempted implicit cast from *const T to []T
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:3:23: error: expected type '[]u32', found '*const u32'
|
||||
|
||||
@ -4,6 +4,8 @@ comptime {
|
||||
_ = aligned;
|
||||
}
|
||||
|
||||
// bad @alignCast at comptime
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:3:35: error: pointer address 0x1 is not aligned to 4 bytes
|
||||
|
||||
@ -0,0 +1,12 @@
|
||||
export fn entry() void {
|
||||
var ptr: fn () callconv(.Async) void = func;
|
||||
var bytes: [64]u8 = undefined;
|
||||
_ = @asyncCall(&bytes, {}, ptr, .{});
|
||||
}
|
||||
fn func() callconv(.Async) void {}
|
||||
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=aarch64-linux-none
|
||||
//
|
||||
// tmp.zig:4:21: error: expected type '[]align(8) u8', found '*[64]u8'
|
||||
@ -4,6 +4,8 @@ export fn a() void {
|
||||
_ = y;
|
||||
}
|
||||
|
||||
// bad alignment in implicit cast from array pointer to slice
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:3:30: error: expected type '[]align(16) u8', found '*[10]u8'
|
||||
|
||||
@ -7,7 +7,9 @@ export fn entry2() void {
|
||||
_ = x;
|
||||
}
|
||||
|
||||
// bad alignment type
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:2:20: error: expected type 'u29', found 'bool'
|
||||
// tmp.zig:6:19: error: fractional component prevents float value 12.340000 from being casted to type 'u29'
|
||||
|
||||
@ -10,6 +10,8 @@ export fn entry() void {
|
||||
_ = Block;
|
||||
}
|
||||
|
||||
// bad identifier in function with struct defined inside function which references local const
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:8:5: error: use of undeclared identifier 'bogus'
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
const bogus = @import("bogus-does-not-exist.zig",);
|
||||
|
||||
// bad import
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:1:23: error: unable to load '${DIR}bogus-does-not-exist.zig': FileNotFound
|
||||
|
||||
@ -19,7 +19,9 @@ fn bar() callconv(.Inline) void {}
|
||||
fn baz1() void {}
|
||||
fn baz2() void {}
|
||||
|
||||
// bad usage of @call
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:2:21: error: expected tuple or struct, found 'void'
|
||||
// tmp.zig:5:14: error: unable to perform 'never_inline' call at compile-time
|
||||
|
||||
@ -3,6 +3,8 @@ comptime {
|
||||
a &= a;
|
||||
}
|
||||
|
||||
// bin and assign on undefined value
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:3:5: error: use of undefined value here causes undefined behavior
|
||||
|
||||
@ -3,6 +3,8 @@ comptime {
|
||||
_ = a & a;
|
||||
}
|
||||
|
||||
// bin and on undefined value
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:3:9: error: use of undefined value here causes undefined behavior
|
||||
|
||||
@ -3,6 +3,8 @@ comptime {
|
||||
_ = ~a;
|
||||
}
|
||||
|
||||
// bin not on undefined value
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:3:10: error: use of undefined value here causes undefined behavior
|
||||
|
||||
@ -3,6 +3,8 @@ comptime {
|
||||
a |= a;
|
||||
}
|
||||
|
||||
// bin or assign on undefined value
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:3:5: error: use of undefined value here causes undefined behavior
|
||||
|
||||
@ -3,6 +3,8 @@ comptime {
|
||||
_ = a | a;
|
||||
}
|
||||
|
||||
// bin or on undefined value
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:3:9: error: use of undefined value here causes undefined behavior
|
||||
|
||||
@ -3,6 +3,8 @@ comptime {
|
||||
a ^= a;
|
||||
}
|
||||
|
||||
// bin xor assign on undefined value
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:3:5: error: use of undefined value here causes undefined behavior
|
||||
|
||||
@ -3,6 +3,8 @@ comptime {
|
||||
_ = a ^ a;
|
||||
}
|
||||
|
||||
// bin xor on undefined value
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:3:9: error: use of undefined value here causes undefined behavior
|
||||
|
||||
@ -4,6 +4,8 @@ var block_aligned_stuff: usize = (4 + TINY_QUANTUM_SIZE) & ~(TINY_QUANTUM_SIZE -
|
||||
|
||||
export fn entry() usize { return @sizeOf(@TypeOf(block_aligned_stuff)); }
|
||||
|
||||
// binary not on number literal
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:3:60: error: unable to perform binary not operation on type 'comptime_int'
|
||||
|
||||
@ -3,6 +3,8 @@ export fn entry(byte: u8) void {
|
||||
_ = oops;
|
||||
}
|
||||
|
||||
// @bitCast same size but bit count mismatch
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:2:25: error: destination type 'u7' has 7 bits but source type 'u8' has 8 bits
|
||||
|
||||
@ -3,6 +3,8 @@ export fn entry() void {
|
||||
_ = y;
|
||||
}
|
||||
|
||||
// bitCast to enum type
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:2:24: error: cannot cast a value of type 'y'
|
||||
|
||||
@ -3,6 +3,8 @@ export fn entry() void {
|
||||
_ = foo;
|
||||
}
|
||||
|
||||
// @bitCast with different sizes inside an expression
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:2:25: error: destination type 'u8' has size 1 but source type 'f32' has size 4
|
||||
|
||||
@ -3,6 +3,8 @@ export fn entry() void {
|
||||
_ = x;
|
||||
}
|
||||
|
||||
// bit shifting only works on integer types
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:2:16: error: bit shifting operation expected integer type, found '*const u8'
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
const x = @import("builtin").bogus;
|
||||
export fn entry() usize { return @sizeOf(@TypeOf(x)); }
|
||||
|
||||
// bogus compile var
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:1:29: error: container 'builtin' has no member called 'bogus'
|
||||
|
||||
@ -4,6 +4,8 @@ fn f(m: []const u8) void {
|
||||
}
|
||||
export fn entry() usize { return @sizeOf(@TypeOf(f)); }
|
||||
|
||||
// bogus method call on slice
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:3:6: error: no member named 'copy' in '[]const u8'
|
||||
|
||||
@ -3,6 +3,8 @@ comptime {
|
||||
_ = !a;
|
||||
}
|
||||
|
||||
// bool not on undefined value
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:3:10: error: use of undefined value here causes undefined behavior
|
||||
|
||||
@ -2,6 +2,8 @@ const x = if (undefined) true else false;
|
||||
|
||||
export fn entry() usize { return @sizeOf(@TypeOf(x)); }
|
||||
|
||||
// branch on undefined value
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:1:15: error: use of undefined value here causes undefined behavior
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
const c = @cImport(@cInclude("bogus.h"));
|
||||
export fn entry() usize { return @sizeOf(@TypeOf(c.bogo)); }
|
||||
|
||||
// @cImport with bogus include
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:1:11: error: C import failed
|
||||
// .h:1:10: note: 'bogus.h' file not found
|
||||
|
||||
@ -16,7 +16,9 @@ export fn entry1() void {
|
||||
baz = bar(42);
|
||||
}
|
||||
|
||||
// call assigned to constant
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:12:14: error: cannot assign to constant
|
||||
// tmp.zig:16:14: error: cannot assign to constant
|
||||
|
||||
@ -0,0 +1,11 @@
|
||||
var buf: [10]u8 align(16) = undefined;
|
||||
export fn entry() void {
|
||||
@call(.{ .stack = &buf }, foo, .{});
|
||||
}
|
||||
fn foo() void {}
|
||||
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=wasm32-wasi-none
|
||||
//
|
||||
// tmp.zig:3:5: error: target arch 'wasm32' does not support calling with a new stack
|
||||
@ -0,0 +1,11 @@
|
||||
export fn entry1() callconv(.APCS) void {}
|
||||
export fn entry2() callconv(.AAPCS) void {}
|
||||
export fn entry3() callconv(.AAPCSVFP) void {}
|
||||
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=x86_64-linux-none
|
||||
//
|
||||
// tmp.zig:1:29: error: callconv 'APCS' is only available on ARM, not x86_64
|
||||
// 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
|
||||
@ -0,0 +1,7 @@
|
||||
export fn entry() callconv(.Interrupt) void {}
|
||||
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=aarch64-linux-none
|
||||
//
|
||||
// tmp.zig:1:28: error: callconv 'Interrupt' is only available on x86, x86_64, AVR, and MSP430, not aarch64
|
||||
@ -0,0 +1,7 @@
|
||||
export fn entry() callconv(.Signal) void {}
|
||||
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=x86_64-linux-none
|
||||
//
|
||||
// tmp.zig:1:28: error: callconv 'Signal' is only available on AVR, not x86_64
|
||||
@ -0,0 +1,23 @@
|
||||
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;
|
||||
_ = a;
|
||||
}
|
||||
export fn entry2() void {
|
||||
var a: F2 = undefined;
|
||||
_ = a;
|
||||
}
|
||||
export fn entry3() void {
|
||||
var a: F3 = undefined;
|
||||
_ = a;
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=x86_64-linux-none
|
||||
//
|
||||
// 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
|
||||
@ -0,0 +1,11 @@
|
||||
export fn entry1() callconv(.Stdcall) void {}
|
||||
export fn entry2() callconv(.Fastcall) void {}
|
||||
export fn entry3() callconv(.Thiscall) void {}
|
||||
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=x86_64-linux-none
|
||||
//
|
||||
// tmp.zig:1:29: error: callconv 'Stdcall' is only available on x86, not x86_64
|
||||
// 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
|
||||
@ -0,0 +1,7 @@
|
||||
export fn entry() callconv(.Vectorcall) void {}
|
||||
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=x86_64-linux-none
|
||||
//
|
||||
// tmp.zig:1:28: error: callconv 'Vectorcall' is only available on x86 and AArch64, not x86_64
|
||||
@ -7,6 +7,8 @@ pub fn main() !void {
|
||||
foos[0](true);
|
||||
}
|
||||
|
||||
// calling a generic function only known at runtime
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:7:9: error: calling a generic function requires compile-time known function value
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user