mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Fix error when boolean combined with ??. First checkin of C3 tester (unfinished)
This commit is contained in:
@@ -19,6 +19,11 @@ fn File! open_path(Path path, String mode)
|
||||
return from_handle(os::native_fopen(path.str_view(), mode));
|
||||
}
|
||||
|
||||
fn bool exists(String file) => @pool()
|
||||
{
|
||||
return path::exists(path::temp_new(file)) ?? false;
|
||||
}
|
||||
|
||||
fn File from_handle(CFile file)
|
||||
{
|
||||
return { .file = file };
|
||||
@@ -186,11 +191,15 @@ fn char[]! load_new(String filename, Allocator allocator = allocator::heap())
|
||||
return data[:len];
|
||||
}
|
||||
|
||||
fn char[]! load_path_new(Path path, Allocator allocator = allocator::heap()) => load_new(path.str_view(), allocator);
|
||||
|
||||
fn char[]! load_temp(String filename)
|
||||
{
|
||||
return load_new(filename, allocator::temp());
|
||||
}
|
||||
|
||||
fn char[]! load_path_temp(Path path) => load_temp(path.str_view());
|
||||
|
||||
fn void! save(String filename, char[] data)
|
||||
{
|
||||
File file = open(filename, "wb")!;
|
||||
|
||||
@@ -362,6 +362,11 @@ fn File SubProcess.stdout(&self)
|
||||
return file::from_handle(self.stdout_file);
|
||||
}
|
||||
|
||||
fn File SubProcess.stderr(&self)
|
||||
{
|
||||
return file::from_handle(self.stderr_file);
|
||||
}
|
||||
|
||||
fn CInt! SubProcess.join(&self) @if(env::WIN32)
|
||||
{
|
||||
if (self.stdin_file)
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
- `{| |}` expression blocks deprecated.
|
||||
|
||||
### Fixes
|
||||
- Bug appearing when `??` was combined with boolean in some cases.
|
||||
|
||||
### Stdlib changes
|
||||
|
||||
|
||||
@@ -1247,7 +1247,21 @@ void llvm_set_phi(LLVMValueRef phi, LLVMValueRef val1, LLVMBasicBlockRef block1,
|
||||
|
||||
void llvm_new_phi(GenContext *c, BEValue *value, const char *name, Type *type, LLVMValueRef val1, LLVMBasicBlockRef block1, LLVMValueRef val2, LLVMBasicBlockRef block2)
|
||||
{
|
||||
LLVMValueRef phi = LLVMBuildPhi(c->builder, LLVMTypeOf(val1), name);
|
||||
LLVMTypeRef ret_type = LLVMTypeOf(val1);
|
||||
LLVMTypeRef other_type = LLVMTypeOf(val2);
|
||||
if (ret_type != other_type)
|
||||
{
|
||||
if (ret_type == c->bool_type)
|
||||
{
|
||||
val2 = LLVMBuildTrunc(c->builder, val2, ret_type, "");
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(other_type == c->bool_type);
|
||||
val2 = LLVMBuildZExt(c->builder, val2, ret_type, "");
|
||||
}
|
||||
}
|
||||
LLVMValueRef phi = LLVMBuildPhi(c->builder, ret_type, name);
|
||||
llvm_set_phi(phi, val1, block1, val2, block2);
|
||||
llvm_value_set(value, phi, type);
|
||||
}
|
||||
|
||||
406
test/src/tester.c3
Normal file
406
test/src/tester.c3
Normal file
@@ -0,0 +1,406 @@
|
||||
import std::io;
|
||||
import std::io::file;
|
||||
import libc;
|
||||
import std::math;
|
||||
import std::collections::map;
|
||||
import std::collections::list;
|
||||
import std::core::dstring;
|
||||
import std::os::process;
|
||||
|
||||
def StringMap = HashMap{String, String};
|
||||
def StringList = List{String};
|
||||
|
||||
String appname;
|
||||
Path compiler_path;
|
||||
int test_count;
|
||||
int skip_count;
|
||||
int success_count;
|
||||
Path start_cwd;
|
||||
Path test_dir;
|
||||
|
||||
fn void arg_error_exit(String fmt, args...) @noreturn
|
||||
{
|
||||
io::printfn(fmt, ...args);
|
||||
usage();
|
||||
}
|
||||
|
||||
fn void error_exit(String fmt, args...) @noreturn
|
||||
{
|
||||
io::printfn(fmt, ...args);
|
||||
libc::exit(1);
|
||||
}
|
||||
|
||||
|
||||
fn void main(String[] args)
|
||||
{
|
||||
appname = args[0];
|
||||
args = { "foo", "../cmake-build-debug-latest/c3c", "test_suite/" };
|
||||
if (args.len < 3 || args.len > 4) usage();
|
||||
|
||||
// Check compiler path
|
||||
start_cwd = path::temp_cwd()!!;
|
||||
test_dir = start_cwd.temp_append("_c3test")!!;
|
||||
Path! path = start_cwd.temp_append(args[1]);
|
||||
if (catch path) arg_error_exit("Invalid compiler path: %s", args[1]);
|
||||
|
||||
if (!path::is_file(path))
|
||||
{
|
||||
error_exit("Error: Invalid path to compiler: %s", path.path_string);
|
||||
}
|
||||
compiler_path = path;
|
||||
|
||||
bool only_skipped = args.len == 4;
|
||||
|
||||
if (only_skipped && args[3] != "-s" && args[3] != "--skipped") usage();
|
||||
|
||||
Path! file = path::temp_new(args[2]);
|
||||
if (catch file) arg_error_exit("Invalid path: '%s'.", args[2]);
|
||||
|
||||
switch
|
||||
{
|
||||
case path::is_file(file):
|
||||
test_file(file);
|
||||
case path::is_dir(file):
|
||||
test_path(file)!!;
|
||||
default:
|
||||
error_exit("Error: Path wasn't to directory or file: %s", file);
|
||||
}
|
||||
|
||||
io::printfn("Found %d tests: %.1f%% (%d / %d) passed (%d skipped).",
|
||||
test_count, 100 * success_count / math::max(1, test_count - skip_count),
|
||||
success_count, test_count - skip_count, skip_count);
|
||||
libc::exit(success_count == test_count - skip_count ? 0 : 1);
|
||||
}
|
||||
|
||||
struct Error
|
||||
{
|
||||
int line;
|
||||
String text;
|
||||
}
|
||||
struct RunFile
|
||||
{
|
||||
String name;
|
||||
File file;
|
||||
int line_offset;
|
||||
List{String} expected_lines;
|
||||
List{Error} warnings;
|
||||
List{Error} errors;
|
||||
bool is_llvm;
|
||||
}
|
||||
|
||||
fn void RunFile.add_line(&self, String line)
|
||||
{
|
||||
if (self.is_llvm)
|
||||
{
|
||||
line = line.trim();
|
||||
if (line == "") return;
|
||||
self.expected_lines.push(line);
|
||||
}
|
||||
else
|
||||
{
|
||||
io::fprintn(&self.file, line)!!;
|
||||
}
|
||||
}
|
||||
|
||||
fn RunFile*! create_file(String filename, bool llvm = false)
|
||||
{
|
||||
File file = file::open_path(test_dir.temp_append(filename), "wb")!;
|
||||
RunFile *run_file = mem::temp_new(RunFile, { .name = filename, .file = file, .is_llvm = llvm });
|
||||
run_file.warnings.temp_init();
|
||||
run_file.errors.temp_init();
|
||||
if (llvm) run_file.expected_lines.temp_init();
|
||||
return run_file;
|
||||
}
|
||||
|
||||
fn void RunFile.close(&self)
|
||||
{
|
||||
(void)self.file.close();
|
||||
}
|
||||
|
||||
struct RunSettings
|
||||
{
|
||||
bool safe;
|
||||
bool debuginfo;
|
||||
bool no_deprecation;
|
||||
List{String} opts;
|
||||
String arch;
|
||||
RunFile* current_file;
|
||||
List{RunFile*} files;
|
||||
}
|
||||
|
||||
fn bool check_line(RunSettings*, String type, String file, String line, String col, String message)
|
||||
{
|
||||
return false;
|
||||
/*
|
||||
def check_line(self, typ, file, line, col, message):
|
||||
map_ = {}
|
||||
if typ == 'Error':
|
||||
map_ = self.errors
|
||||
elif typ == 'Warning':
|
||||
map_ = self.warnings
|
||||
else:
|
||||
self.exit_error("Unknown type: " + typ)
|
||||
file = os.path.basename(file)
|
||||
key = file + ":" + line
|
||||
value = map_.get(key)
|
||||
if value is None:
|
||||
return False
|
||||
if value in message:
|
||||
del map_[key]
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
*/
|
||||
}
|
||||
fn bool parse_result(DString out, RunSettings settings)
|
||||
{
|
||||
// Inefficient, fix.
|
||||
bool success = true;
|
||||
foreach (line : out.str_view().tsplit("\n"))
|
||||
{
|
||||
if (!line) continue;
|
||||
String[] parts = line.tsplit("|", 5);
|
||||
if (parts.len != 5)
|
||||
{
|
||||
error_exit("Unexpected error: %s", out);
|
||||
}
|
||||
if (!check_line(&settings, ...parts[:5]))
|
||||
{
|
||||
parts[0].convert_ascii_to_lower();
|
||||
io::printf("Unexpected %s in %s line %s:", parts[0], path::temp_new(parts[1]).basename()!!, parts[2]);
|
||||
io::printfn(`"%s"`, parts[4]);
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
int not_found_errors, not_found_warnings;
|
||||
foreach (file : settings.files)
|
||||
{
|
||||
if (file.errors.len())
|
||||
{
|
||||
success = false;
|
||||
if (!not_found_errors) io::printn("Errors that never occurred:");
|
||||
foreach (i, &item : file.errors)
|
||||
{
|
||||
io::printfn(`%d. %s %d expected: "%s"`, ++not_found_errors, file.name, item.line, item.text);
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (file : settings.files)
|
||||
{
|
||||
if (file.warnings.len())
|
||||
{
|
||||
success = false;
|
||||
if (!not_found_warnings) io::printn("Warnings that never occurred:");
|
||||
foreach (i, &item : file.warnings)
|
||||
{
|
||||
io::printfn(`%d. %s %d expected: "%s"`, ++not_found_warnings, file.name, item.line, item.text);
|
||||
}
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
fn void parse_trailing_directive(int line_number, String line, RunSettings* settings, bool is_single)
|
||||
{
|
||||
usz index = line.rindex_of("// #")!! + 4;
|
||||
line = line[index..].trim();
|
||||
switch
|
||||
{
|
||||
case line.starts_with("warning:"):
|
||||
line = line[8..].trim();
|
||||
settings.current_file.warnings.push({ line_number, line });
|
||||
case line.starts_with("error:"):
|
||||
line = line[6..].trim();
|
||||
settings.current_file.errors.push({ line_number, line });
|
||||
default:
|
||||
error_exit("Unknown trailing directive '%s'", line);
|
||||
}
|
||||
}
|
||||
fn void parse_header_directive(int line_no, String line, RunSettings* settings, bool is_single)
|
||||
{
|
||||
line = line[4..].trim();
|
||||
switch
|
||||
{
|
||||
case line.starts_with("error:"):
|
||||
line = line[6..].trim();
|
||||
settings.current_file.errors.push({ line_no, line });
|
||||
case line.starts_with("safe:"):
|
||||
settings.safe = line[5..].trim() == "yes";
|
||||
case line.starts_with("debuginfo:"):
|
||||
settings.debuginfo = line[10..].trim() == "yes";
|
||||
case line.starts_with("opt:"):
|
||||
settings.opts.push(line[4..].trim());
|
||||
case line.starts_with("target:"):
|
||||
settings.arch = line[7..].trim();
|
||||
case line.starts_with("deprecation:"):
|
||||
settings.no_deprecation = line[12..].trim() == "no";
|
||||
case line.starts_with("file:"):
|
||||
if (is_single) error_exit("'file' directive only allowed with .c3t");
|
||||
settings.current_file.close();
|
||||
line = line[5..].trim();
|
||||
RunFile* file = settings.current_file = create_file(line)!!;
|
||||
settings.files.push(file);
|
||||
settings.current_file = file;
|
||||
case line.starts_with("expect:"):
|
||||
if (is_single) error_exit("'expect' directive only allowed with .c3t");
|
||||
line = line[7..].trim();
|
||||
settings.current_file.close();
|
||||
RunFile* file = settings.current_file = create_file(line, llvm: true)!!;
|
||||
settings.files.push(file);
|
||||
default:
|
||||
io::printfn("Unknown header directive '%s'", line);
|
||||
libc::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
fn void test_file(Path file_path)
|
||||
{
|
||||
io::printfn("Checking %s", file_path);
|
||||
static int count = 1;
|
||||
bool single;
|
||||
(void)path::rmtree(test_dir);
|
||||
if (@catch(path::mkdir(test_dir)))
|
||||
{
|
||||
io::printfn("Failed to create temp test directory '%s'.", test_dir);
|
||||
libc::exit(1);
|
||||
}
|
||||
switch (file_path.extension() ?? "")
|
||||
{
|
||||
case "c3":
|
||||
single = true;
|
||||
case "c3t":
|
||||
single = false;
|
||||
default:
|
||||
io::printfn("Unexpected file name '%s', expected a file with a '.c3' or '.c3t' suffix.", file_path.str_view());
|
||||
libc::exit(1);
|
||||
}
|
||||
File! f = file::open_path(file_path, "rb");
|
||||
if (catch f)
|
||||
{
|
||||
io::printfn("Error: Failed to open '%s'.", file_path);
|
||||
libc::exit(1);
|
||||
}
|
||||
defer (void)f.close();
|
||||
RunSettings settings;
|
||||
settings.opts.temp_init();
|
||||
settings.files.temp_init();
|
||||
settings.current_file = create_file(file_path.basename()[..^(single ? 4 : 5)].tconcat(".c3"))!!;
|
||||
settings.files.push(settings.current_file);
|
||||
int line_no = 0;
|
||||
while (try line = io::treadline(&f))
|
||||
{
|
||||
if (line.starts_with("// #") || line.starts_with("/* #"))
|
||||
{
|
||||
parse_header_directive(line_no, line, &settings, single);
|
||||
continue;
|
||||
}
|
||||
else if (line.contains("// #"))
|
||||
{
|
||||
parse_trailing_directive(line_no, line, &settings, single);
|
||||
continue;
|
||||
}
|
||||
settings.current_file.add_line(line);
|
||||
line_no++;
|
||||
}
|
||||
settings.current_file.close();
|
||||
test_count += 1;
|
||||
DString cmdline = dstring::temp_new(compiler_path.str_view());
|
||||
cmdline.append(" compile-only --test ");
|
||||
foreach (file : settings.files)
|
||||
{
|
||||
if (file.is_llvm) continue;
|
||||
cmdline.append(file.name);
|
||||
cmdline.append(" ");
|
||||
}
|
||||
if (!single) cmdline.append("--emit-llvm ");
|
||||
cmdline.append(settings.debuginfo ? "-g " : "-g0 ");
|
||||
if (settings.arch) cmdline.appendf("--target %s ", settings.arch);
|
||||
cmdline.append("-O0 ");
|
||||
if (settings.no_deprecation) cmdline.append("--silence-deprecation ");
|
||||
cmdline.append(settings.safe ? "--safe=yes " : "--safe=no ");
|
||||
foreach (opt : settings.opts)
|
||||
{
|
||||
cmdline.appendf("%s ", opt);
|
||||
}
|
||||
io::printfn("Dir: %s", test_dir);
|
||||
path::chdir(test_dir)!!;
|
||||
io::printn(cmdline);
|
||||
SubProcess compilation = process::create(cmdline.str_view().trim().tsplit(" "), { .search_user_path = true })!!;
|
||||
CInt result = compilation.join()!!;
|
||||
DString out = dstring::temp_new();
|
||||
io::copy_to(&&compilation.stderr(), &out)!!;
|
||||
if (result != 0 && result != 1)
|
||||
{
|
||||
io::printfn("Error(%s): ", result, out);
|
||||
return;
|
||||
}
|
||||
if (!parse_result(out, settings)) return;
|
||||
foreach (file : settings.files)
|
||||
{
|
||||
if (!file.is_llvm) continue;
|
||||
if (!file::exists(file.name))
|
||||
{
|
||||
io::printfn("Did not compile file %s.", file.name);
|
||||
return;
|
||||
}
|
||||
File file_ll = file::open(file.name, "rb")!!;
|
||||
defer (void)file_ll.close();
|
||||
String! next = file.expected_lines.pop_first();
|
||||
while (try line = io::treadline(&file_ll) && try value = next)
|
||||
{
|
||||
line = line.trim();
|
||||
if (line == "") continue;
|
||||
if (line.contains(value))
|
||||
{
|
||||
next = file.expected_lines.pop_first();
|
||||
}
|
||||
}
|
||||
if (try next)
|
||||
{
|
||||
io::printfn(`%s did not contain: "%s"`, file.name, next);
|
||||
io::printfn("\n\n\n---------------------------------------------------> %s\n\n", file.name);
|
||||
(void)file_ll.seek(0);
|
||||
(void)io::printn((String)io::read_new_fully(&file_ll, allocator: allocator::temp()));
|
||||
io::printfn("<---------------------------------------------------- %s\n", file_path);
|
||||
return;
|
||||
}
|
||||
}
|
||||
success_count++;
|
||||
}
|
||||
|
||||
fn void! test_path(Path file_path)
|
||||
{
|
||||
(void)path::chdir(start_cwd);
|
||||
foreach (file : path::temp_ls(file_path)!!)
|
||||
{
|
||||
@pool()
|
||||
{
|
||||
(void)path::chdir(start_cwd);
|
||||
file = file_path.temp_append(file.str_view())!;
|
||||
switch
|
||||
{
|
||||
case path::is_dir(file):
|
||||
test_path(file)!;
|
||||
case path::is_file(file):
|
||||
switch (file.extension() ?? "")
|
||||
{
|
||||
case "c3":
|
||||
case "c3t":
|
||||
test_file(file);
|
||||
}
|
||||
default:
|
||||
io::printfn("Skip %s", file);
|
||||
// Ignore
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn void usage() @noreturn
|
||||
{
|
||||
io::printfn("Usage: %s <compiler path> <file/dir> [-s]", appname);
|
||||
io::printn();
|
||||
io::printn("Options:");
|
||||
io::printn(" -s, --skipped only run skipped tests");
|
||||
libc::exit(0);
|
||||
}
|
||||
@@ -18,7 +18,3 @@ fn void main()
|
||||
Bob gh;
|
||||
gh += 1; // #error: A value of type 'Bob'
|
||||
}
|
||||
|
||||
/* #expect: test.ll
|
||||
|
||||
feofke
|
||||
@@ -1,88 +0,0 @@
|
||||
// #target: macos-x64
|
||||
module test;
|
||||
|
||||
fn void! foo()
|
||||
{}
|
||||
|
||||
fault Abc { AAA }
|
||||
|
||||
macro int! bar()
|
||||
{
|
||||
return Abc.AAA?;
|
||||
}
|
||||
|
||||
fn int! baz()
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
fn int main()
|
||||
{
|
||||
int x;
|
||||
int! y;
|
||||
(void)x;
|
||||
(void)y;
|
||||
(void)foo();
|
||||
(void)bar();
|
||||
(void)(bar() + 1);
|
||||
(void)baz();
|
||||
(void)(baz() + 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* #expect: test.ll
|
||||
define i32 @main() #0 {
|
||||
entry:
|
||||
%x = alloca i32, align 4
|
||||
%y = alloca i32, align 4
|
||||
%y.f = alloca i64, align 8
|
||||
%retparam = alloca i32, align 4
|
||||
%retparam9 = alloca i32, align 4
|
||||
store i32 0, ptr %x, align 4
|
||||
store i64 0, ptr %y.f, align 8
|
||||
store i32 0, ptr %y, align 4
|
||||
%0 = load i32, ptr %x, align 4
|
||||
%optval = load i64, ptr %y.f, align 8
|
||||
%not_err = icmp eq i64 %optval, 0
|
||||
br i1 %not_err, label %after_check, label %end_block
|
||||
|
||||
after_check: ; preds = %entry
|
||||
%1 = load i32, ptr %y, align 4
|
||||
br label %end_block
|
||||
|
||||
end_block: ; preds = %after_check, %entry
|
||||
%2 = call i64 @test.foo()
|
||||
%not_err1 = icmp eq i64 %2, 0
|
||||
br i1 %not_err1, label %after_check2, label %end_block3
|
||||
|
||||
after_check2: ; preds = %end_block
|
||||
br label %end_block3
|
||||
|
||||
end_block3: ; preds = %after_check2, %end_block
|
||||
br label %end_block4
|
||||
|
||||
end_block4: ; preds = %end_block3
|
||||
br label %end_block5
|
||||
|
||||
end_block5: ; preds = %end_block4
|
||||
%3 = call i64 @test.baz(ptr %retparam)
|
||||
%not_err6 = icmp eq i64 %3, 0
|
||||
br i1 %not_err6, label %after_check7, label %end_block8
|
||||
|
||||
after_check7: ; preds = %end_block5
|
||||
%4 = load i32, ptr %retparam, align 4
|
||||
br label %end_block8
|
||||
|
||||
end_block8: ; preds = %after_check7, %end_block5
|
||||
%5 = call i64 @test.baz(ptr %retparam9)
|
||||
%not_err10 = icmp eq i64 %5, 0
|
||||
br i1 %not_err10, label %after_check11, label %end_block12
|
||||
|
||||
after_check11: ; preds = %end_block8
|
||||
%6 = load i32, ptr %retparam9, align 4
|
||||
%add = add i32 %6, 1
|
||||
br label %end_block12
|
||||
|
||||
end_block12: ; preds = %after_check11, %end_block8
|
||||
ret i32 1
|
||||
}
|
||||
62
test/test_suite/expressions/casts/void_casting.c3t
Normal file
62
test/test_suite/expressions/casts/void_casting.c3t
Normal file
@@ -0,0 +1,62 @@
|
||||
// #target: macos-x64
|
||||
module test;
|
||||
|
||||
fn void! foo()
|
||||
{}
|
||||
|
||||
fault Abc { AAA }
|
||||
|
||||
macro int! bar()
|
||||
{
|
||||
return Abc.AAA?;
|
||||
}
|
||||
|
||||
fn int! baz()
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
fn int main()
|
||||
{
|
||||
int x;
|
||||
int! y;
|
||||
(void)x;
|
||||
(void)y;
|
||||
(void)foo();
|
||||
(void)bar();
|
||||
(void)(bar() + 1);
|
||||
(void)baz();
|
||||
(void)(baz() + 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* #expect: test.ll
|
||||
|
||||
define i32 @main() #0 {
|
||||
entry:
|
||||
%x = alloca i32, align 4
|
||||
%y = alloca i32, align 4
|
||||
%y.f = alloca i64, align 8
|
||||
%retparam = alloca i32, align 4
|
||||
%retparam2 = alloca i32, align 4
|
||||
store i32 0, ptr %x, align 4
|
||||
store i64 0, ptr %y.f, align 8
|
||||
store i32 0, ptr %y, align 4
|
||||
%optval = load i64, ptr %y.f, align 8
|
||||
%0 = call i64 @test.foo()
|
||||
br label %postfailed
|
||||
postfailed: ; preds = %entry
|
||||
br label %postfailed1
|
||||
postfailed1: ; preds = %postfailed
|
||||
%1 = call i64 @test.baz(ptr %retparam)
|
||||
%2 = call i64 @test.baz(ptr %retparam2)
|
||||
%not_err = icmp eq i64 %2, 0
|
||||
%3 = call i1 @llvm.expect.i1(i1 %not_err, i1 true)
|
||||
br i1 %3, label %after_check, label %voiderr
|
||||
after_check: ; preds = %postfailed1
|
||||
%4 = load i32, ptr %retparam2, align 4
|
||||
%add = add i32 %4, 1
|
||||
br label %voiderr
|
||||
voiderr: ; preds = %after_check, %postfailed1
|
||||
ret i32 1
|
||||
}
|
||||
Reference in New Issue
Block a user