checker: `[noreturn]` part 2 (cleanup) (#10667)

pull/10669/head
Delyan Angelov 2021-07-05 05:05:37 +03:00 committed by GitHub
parent da9c75f2ca
commit 972542d6ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 82 additions and 26 deletions

View File

@ -480,6 +480,7 @@ fn (t Tree) fn_decl(node ast.FnDecl) &Node {
obj.add('is_pub', t.bool_node(node.is_pub))
obj.add('is_variadic', t.bool_node(node.is_variadic))
obj.add('is_anon', t.bool_node(node.is_anon))
obj.add('is_noreturn', t.bool_node(node.is_noreturn))
obj.add('is_manualfree', t.bool_node(node.is_manualfree))
obj.add('is_main', t.bool_node(node.is_main))
obj.add('is_test', t.bool_node(node.is_test))
@ -1393,22 +1394,24 @@ fn (t Tree) ident_fn(node ast.IdentFn) &Node {
fn (t Tree) call_expr(node ast.CallExpr) &Node {
mut obj := new_object()
obj.add('ast_type', t.string_node('CallExpr'))
obj.add('left', t.expr(node.left))
obj.add('is_method', t.bool_node(node.is_method))
obj.add('mod', t.string_node(node.mod))
obj.add('name', t.string_node(node.name))
obj.add('language', t.enum_node(node.language))
obj.add('left_type', t.type_node(node.left_type))
obj.add('receiver_type', t.type_node(node.receiver_type))
obj.add('return_type', t.type_node(node.return_type))
obj.add('left', t.expr(node.left))
obj.add('is_method', t.bool_node(node.is_method))
obj.add('is_keep_alive', t.bool_node(node.is_keep_alive))
obj.add('is_noreturn', t.bool_node(node.is_noreturn))
obj.add('should_be_skipped', t.bool_node(node.should_be_skipped))
obj.add('free_receiver', t.bool_node(node.free_receiver))
obj.add('scope', t.number_node(int(node.scope)))
obj.add('args', t.array_node_call_arg(node.args))
obj.add('expected_arg_types', t.array_node_type(node.expected_arg_types))
obj.add('concrete_types', t.array_node_type(node.concrete_types))
obj.add('or_block', t.or_expr(node.or_block))
obj.add('left_type', t.type_node(node.left_type))
obj.add('receiver_type', t.type_node(node.receiver_type))
obj.add('return_type', t.type_node(node.return_type))
obj.add('should_be_skipped', t.bool_node(node.should_be_skipped))
obj.add('concrete_list_pos', t.position(node.concrete_list_pos))
obj.add('free_receiver', t.bool_node(node.free_receiver))
obj.add('from_embed_type', t.type_node(node.from_embed_type))
obj.add('comments', t.array_node_comment(node.comments))
obj.add('pos', t.position(node.pos))

View File

@ -332,6 +332,7 @@ fn get_compile_name_of_potential_v_project(file string) string {
return pfolder
}
[noreturn]
fn verror(s string) {
util.verror('vfmt error', s)
}

View File

@ -13,7 +13,6 @@ fn vhalt() {
[noreturn]
pub fn exit(code int) {
C.exit(code)
vhalt()
}
fn vcommithash() string {

View File

@ -16,7 +16,7 @@ fn C.realloc(a &byte, b int) &byte
fn C.free(ptr voidptr)
[trusted]
[noreturn; trusted]
fn C.exit(code int)
fn C.qsort(base voidptr, items size_t, item_size size_t, cb qsort_callback_func)

View File

@ -343,12 +343,12 @@ fn test_realpath_does_not_absolutize_non_existing_relative_paths() {
}
}
fn test_realpath_absolutepath_symlink() {
fn test_realpath_absolutepath_symlink() ? {
file_name := 'tolink_file.txt'
symlink_name := 'symlink.txt'
mut f := os.create(file_name) or { panic(err) }
mut f := os.create(file_name) ?
f.close()
assert os.symlink(file_name, symlink_name) or { panic(err) }
assert os.symlink(file_name, symlink_name) ?
rpath := os.real_path(symlink_name)
println(rpath)
assert os.is_abs_path(rpath)

View File

@ -461,6 +461,7 @@ fn error_with_pos(s string, fpath string, pos token.Position) {
exit(1)
}
[noreturn]
fn verror(s string) {
util.verror('builder error', s)
}

View File

@ -30,7 +30,6 @@ pub fn compile(command string, pref &pref.Preferences) {
os.is_writable_folder(output_folder) or {
// An early error here, is better than an unclear C error later:
verror(err.msg)
exit(1)
}
// Construct the V object from command line arguments
mut b := new_builder(pref)
@ -217,9 +216,7 @@ pub fn (v Builder) get_builtin_files() []string {
}
}
// Panic. We couldn't find the folder.
verror('`builtin/` not included on module lookup path.
Did you forget to add vlib to the path? (Use @vlib for default vlib)')
panic('Unreachable code reached.')
verror('`builtin/` not included on module lookup path.\nDid you forget to add vlib to the path? (Use @vlib for default vlib)')
}
pub fn (v &Builder) get_user_files() []string {
@ -259,10 +256,7 @@ pub fn (v &Builder) get_user_files() []string {
is_test := v.pref.is_test
mut is_internal_module_test := false
if is_test {
tcontent := os.read_file(dir) or {
verror('$dir does not exist')
exit(0)
}
tcontent := os.read_file(dir) or { verror('$dir does not exist') }
slines := tcontent.trim_space().split_into_lines()
for sline in slines {
line := sline.trim_space()
@ -290,7 +284,6 @@ pub fn (v &Builder) get_user_files() []string {
does_exist := os.exists(dir)
if !does_exist {
verror("$dir doesn't exist")
exit(1)
}
is_real_file := does_exist && !os.is_dir(dir)
resolved_link := if is_real_file && os.is_link(dir) { os.real_path(dir) } else { dir }

View File

@ -4756,10 +4756,31 @@ fn (mut c Checker) stmts(stmts []ast.Stmt) {
if unreachable.line_nr >= 0 {
c.error('unreachable code', unreachable)
}
c.find_unreachable_statements_after_noreturn_calls(stmts)
c.scope_returns = false
c.expected_type = ast.void_type
}
pub fn (mut c Checker) find_unreachable_statements_after_noreturn_calls(stmts []ast.Stmt) {
mut prev_stmt_was_noreturn_call := false
for stmt in stmts {
match stmt {
ast.ExprStmt {
if stmt.expr is ast.CallExpr {
if prev_stmt_was_noreturn_call {
c.error('unreachable code after a [noreturn] call', stmt.pos)
return
}
prev_stmt_was_noreturn_call = stmt.expr.is_noreturn
}
}
else {
prev_stmt_was_noreturn_call = false
}
}
}
}
pub fn (mut c Checker) unwrap_generic(typ ast.Type) ast.Type {
if typ.has_flag(.generic) {
if t_typ := c.table.resolve_generic_to_concrete(typ, c.table.cur_fn.generic_names,

View File

@ -5,3 +5,9 @@ vlib/v/checker/tests/noreturn_with_non_empty_loop_at_end.vv:4:6: error: [noretur
| ^
5 | break
6 | }
vlib/v/checker/tests/noreturn_with_non_empty_loop_at_end.vv:18:2: error: unreachable code after a [noreturn] call
16 | eprintln('start')
17 | abc()
18 | eprintln('done')
| ~~~~~~~~~~~~~~~~
19 | }

View File

@ -11,3 +11,9 @@ vlib/v/checker/tests/noreturn_with_return.vv:6:2: error: [noreturn] functions sh
| ~~~~~~
7 | }
8 |
vlib/v/checker/tests/noreturn_with_return.vv:18:2: error: unreachable code after a [noreturn] call
16 | eprintln('start')
17 | abc()
18 | eprintln('done')
| ~~~~~~~~~~~~~~~~
19 | }

View File

@ -5,3 +5,9 @@ vlib/v/checker/tests/noreturn_without_loop_or_another_noreturn_at_end.vv:3:2: er
| ~~~~~~~~~~~~~
4 | }
5 |
vlib/v/checker/tests/noreturn_without_loop_or_another_noreturn_at_end.vv:15:2: error: unreachable code after a [noreturn] call
13 | eprintln('start')
14 | abc()
15 | eprintln('done')
| ~~~~~~~~~~~~~~~~
16 | }

View File

@ -185,6 +185,23 @@ const c_common_macros = '
#endif
#endif
#if !defined(VUNREACHABLE)
#if defined(__GNUC__) && !defined(__clang__)
#define V_GCC_VERSION (__GNUC__ * 10000L + __GNUC_MINOR__ * 100L + __GNUC_PATCHLEVEL__)
#if (V_GCC_VERSION >= 40500L)
#define VUNREACHABLE() do { __builtin_unreachable(); } while (0)
#endif
#endif
#if defined(__clang__) && defined(__has_builtin)
#if __has_builtin(__builtin_unreachable)
#define VUNREACHABLE() do { __builtin_unreachable(); } while (0)
#endif
#endif
#ifndef VUNREACHABLE
#define VUNREACHABLE() do { } while (0)
#endif
#endif
//likely and unlikely macros
#if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__clang__)
#define _likely_(x) __builtin_expect(x,1)

View File

@ -527,6 +527,10 @@ fn (mut g Gen) call_expr(node ast.CallExpr) {
g.write('\n $cur_line $tmp_opt')
}
}
if node.is_noreturn {
g.writeln(';')
g.write('VUNREACHABLE()')
}
}
fn (mut g Gen) method_call(node ast.CallExpr) {

View File

@ -300,7 +300,7 @@ pub fn (g JsGen) hashes() string {
return res
}
[inline]
[noreturn]
fn verror(msg string) {
eprintln('jsgen error: $msg')
exit(1)

View File

@ -802,10 +802,7 @@ fn (mut g Gen) assign_stmt(node ast.AssignStmt) {
match node.left_types[i] {
7 { // ast.IndexExpr {
ie := node.left[i] as ast.IndexExpr
bracket := name.index('[') or {
verror('bracket expected')
exit(1)
}
bracket := name.index('[') or { verror('bracket expected') }
var_name := name[0..bracket]
mut dest := g.get_var_offset(var_name)
index := ie.index as ast.IntegerLiteral

View File

@ -3218,6 +3218,7 @@ fn (p &Parser) new_true_expr() ast.Expr {
}
}
[noreturn]
fn verror(s string) {
util.verror('parser error', s)
}

View File

@ -1399,6 +1399,7 @@ fn (mut s Scanner) vet_error(msg string, fix vet.FixKind) {
s.vet_errors << ve
}
[noreturn]
pub fn verror(s string) {
util.verror('scanner error', s)
}