mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
checker: [noreturn]
part 2 (cleanup) (#10667)
This commit is contained in:
parent
da9c75f2ca
commit
972542d6ee
@ -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_pub', t.bool_node(node.is_pub))
|
||||||
obj.add('is_variadic', t.bool_node(node.is_variadic))
|
obj.add('is_variadic', t.bool_node(node.is_variadic))
|
||||||
obj.add('is_anon', t.bool_node(node.is_anon))
|
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_manualfree', t.bool_node(node.is_manualfree))
|
||||||
obj.add('is_main', t.bool_node(node.is_main))
|
obj.add('is_main', t.bool_node(node.is_main))
|
||||||
obj.add('is_test', t.bool_node(node.is_test))
|
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 {
|
fn (t Tree) call_expr(node ast.CallExpr) &Node {
|
||||||
mut obj := new_object()
|
mut obj := new_object()
|
||||||
obj.add('ast_type', t.string_node('CallExpr'))
|
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('mod', t.string_node(node.mod))
|
||||||
obj.add('name', t.string_node(node.name))
|
obj.add('name', t.string_node(node.name))
|
||||||
obj.add('language', t.enum_node(node.language))
|
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('scope', t.number_node(int(node.scope)))
|
||||||
obj.add('args', t.array_node_call_arg(node.args))
|
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('expected_arg_types', t.array_node_type(node.expected_arg_types))
|
||||||
obj.add('concrete_types', t.array_node_type(node.concrete_types))
|
obj.add('concrete_types', t.array_node_type(node.concrete_types))
|
||||||
obj.add('or_block', t.or_expr(node.or_block))
|
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('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('from_embed_type', t.type_node(node.from_embed_type))
|
||||||
obj.add('comments', t.array_node_comment(node.comments))
|
obj.add('comments', t.array_node_comment(node.comments))
|
||||||
obj.add('pos', t.position(node.pos))
|
obj.add('pos', t.position(node.pos))
|
||||||
|
@ -332,6 +332,7 @@ fn get_compile_name_of_potential_v_project(file string) string {
|
|||||||
return pfolder
|
return pfolder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[noreturn]
|
||||||
fn verror(s string) {
|
fn verror(s string) {
|
||||||
util.verror('vfmt error', s)
|
util.verror('vfmt error', s)
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,6 @@ fn vhalt() {
|
|||||||
[noreturn]
|
[noreturn]
|
||||||
pub fn exit(code int) {
|
pub fn exit(code int) {
|
||||||
C.exit(code)
|
C.exit(code)
|
||||||
vhalt()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn vcommithash() string {
|
fn vcommithash() string {
|
||||||
|
@ -16,7 +16,7 @@ fn C.realloc(a &byte, b int) &byte
|
|||||||
|
|
||||||
fn C.free(ptr voidptr)
|
fn C.free(ptr voidptr)
|
||||||
|
|
||||||
[trusted]
|
[noreturn; trusted]
|
||||||
fn C.exit(code int)
|
fn C.exit(code int)
|
||||||
|
|
||||||
fn C.qsort(base voidptr, items size_t, item_size size_t, cb qsort_callback_func)
|
fn C.qsort(base voidptr, items size_t, item_size size_t, cb qsort_callback_func)
|
||||||
|
@ -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'
|
file_name := 'tolink_file.txt'
|
||||||
symlink_name := 'symlink.txt'
|
symlink_name := 'symlink.txt'
|
||||||
mut f := os.create(file_name) or { panic(err) }
|
mut f := os.create(file_name) ?
|
||||||
f.close()
|
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)
|
rpath := os.real_path(symlink_name)
|
||||||
println(rpath)
|
println(rpath)
|
||||||
assert os.is_abs_path(rpath)
|
assert os.is_abs_path(rpath)
|
||||||
|
@ -461,6 +461,7 @@ fn error_with_pos(s string, fpath string, pos token.Position) {
|
|||||||
exit(1)
|
exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[noreturn]
|
||||||
fn verror(s string) {
|
fn verror(s string) {
|
||||||
util.verror('builder error', s)
|
util.verror('builder error', s)
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,6 @@ pub fn compile(command string, pref &pref.Preferences) {
|
|||||||
os.is_writable_folder(output_folder) or {
|
os.is_writable_folder(output_folder) or {
|
||||||
// An early error here, is better than an unclear C error later:
|
// An early error here, is better than an unclear C error later:
|
||||||
verror(err.msg)
|
verror(err.msg)
|
||||||
exit(1)
|
|
||||||
}
|
}
|
||||||
// Construct the V object from command line arguments
|
// Construct the V object from command line arguments
|
||||||
mut b := new_builder(pref)
|
mut b := new_builder(pref)
|
||||||
@ -217,9 +216,7 @@ pub fn (v Builder) get_builtin_files() []string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Panic. We couldn't find the folder.
|
// Panic. We couldn't find the folder.
|
||||||
verror('`builtin/` not included on module lookup path.
|
verror('`builtin/` not included on module lookup path.\nDid you forget to add vlib to the path? (Use @vlib for default vlib)')
|
||||||
Did you forget to add vlib to the path? (Use @vlib for default vlib)')
|
|
||||||
panic('Unreachable code reached.')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (v &Builder) get_user_files() []string {
|
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
|
is_test := v.pref.is_test
|
||||||
mut is_internal_module_test := false
|
mut is_internal_module_test := false
|
||||||
if is_test {
|
if is_test {
|
||||||
tcontent := os.read_file(dir) or {
|
tcontent := os.read_file(dir) or { verror('$dir does not exist') }
|
||||||
verror('$dir does not exist')
|
|
||||||
exit(0)
|
|
||||||
}
|
|
||||||
slines := tcontent.trim_space().split_into_lines()
|
slines := tcontent.trim_space().split_into_lines()
|
||||||
for sline in slines {
|
for sline in slines {
|
||||||
line := sline.trim_space()
|
line := sline.trim_space()
|
||||||
@ -290,7 +284,6 @@ pub fn (v &Builder) get_user_files() []string {
|
|||||||
does_exist := os.exists(dir)
|
does_exist := os.exists(dir)
|
||||||
if !does_exist {
|
if !does_exist {
|
||||||
verror("$dir doesn't exist")
|
verror("$dir doesn't exist")
|
||||||
exit(1)
|
|
||||||
}
|
}
|
||||||
is_real_file := does_exist && !os.is_dir(dir)
|
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 }
|
resolved_link := if is_real_file && os.is_link(dir) { os.real_path(dir) } else { dir }
|
||||||
|
@ -4756,10 +4756,31 @@ fn (mut c Checker) stmts(stmts []ast.Stmt) {
|
|||||||
if unreachable.line_nr >= 0 {
|
if unreachable.line_nr >= 0 {
|
||||||
c.error('unreachable code', unreachable)
|
c.error('unreachable code', unreachable)
|
||||||
}
|
}
|
||||||
|
c.find_unreachable_statements_after_noreturn_calls(stmts)
|
||||||
c.scope_returns = false
|
c.scope_returns = false
|
||||||
c.expected_type = ast.void_type
|
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 {
|
pub fn (mut c Checker) unwrap_generic(typ ast.Type) ast.Type {
|
||||||
if typ.has_flag(.generic) {
|
if typ.has_flag(.generic) {
|
||||||
if t_typ := c.table.resolve_generic_to_concrete(typ, c.table.cur_fn.generic_names,
|
if t_typ := c.table.resolve_generic_to_concrete(typ, c.table.cur_fn.generic_names,
|
||||||
|
@ -5,3 +5,9 @@ vlib/v/checker/tests/noreturn_with_non_empty_loop_at_end.vv:4:6: error: [noretur
|
|||||||
| ^
|
| ^
|
||||||
5 | break
|
5 | break
|
||||||
6 | }
|
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 | }
|
||||||
|
@ -11,3 +11,9 @@ vlib/v/checker/tests/noreturn_with_return.vv:6:2: error: [noreturn] functions sh
|
|||||||
| ~~~~~~
|
| ~~~~~~
|
||||||
7 | }
|
7 | }
|
||||||
8 |
|
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 | }
|
||||||
|
@ -5,3 +5,9 @@ vlib/v/checker/tests/noreturn_without_loop_or_another_noreturn_at_end.vv:3:2: er
|
|||||||
| ~~~~~~~~~~~~~
|
| ~~~~~~~~~~~~~
|
||||||
4 | }
|
4 | }
|
||||||
5 |
|
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 | }
|
||||||
|
@ -185,6 +185,23 @@ const c_common_macros = '
|
|||||||
#endif
|
#endif
|
||||||
#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
|
//likely and unlikely macros
|
||||||
#if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__clang__)
|
#if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__clang__)
|
||||||
#define _likely_(x) __builtin_expect(x,1)
|
#define _likely_(x) __builtin_expect(x,1)
|
||||||
|
@ -527,6 +527,10 @@ fn (mut g Gen) call_expr(node ast.CallExpr) {
|
|||||||
g.write('\n $cur_line $tmp_opt')
|
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) {
|
fn (mut g Gen) method_call(node ast.CallExpr) {
|
||||||
|
@ -300,7 +300,7 @@ pub fn (g JsGen) hashes() string {
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
[inline]
|
[noreturn]
|
||||||
fn verror(msg string) {
|
fn verror(msg string) {
|
||||||
eprintln('jsgen error: $msg')
|
eprintln('jsgen error: $msg')
|
||||||
exit(1)
|
exit(1)
|
||||||
|
@ -802,10 +802,7 @@ fn (mut g Gen) assign_stmt(node ast.AssignStmt) {
|
|||||||
match node.left_types[i] {
|
match node.left_types[i] {
|
||||||
7 { // ast.IndexExpr {
|
7 { // ast.IndexExpr {
|
||||||
ie := node.left[i] as ast.IndexExpr
|
ie := node.left[i] as ast.IndexExpr
|
||||||
bracket := name.index('[') or {
|
bracket := name.index('[') or { verror('bracket expected') }
|
||||||
verror('bracket expected')
|
|
||||||
exit(1)
|
|
||||||
}
|
|
||||||
var_name := name[0..bracket]
|
var_name := name[0..bracket]
|
||||||
mut dest := g.get_var_offset(var_name)
|
mut dest := g.get_var_offset(var_name)
|
||||||
index := ie.index as ast.IntegerLiteral
|
index := ie.index as ast.IntegerLiteral
|
||||||
|
@ -3218,6 +3218,7 @@ fn (p &Parser) new_true_expr() ast.Expr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[noreturn]
|
||||||
fn verror(s string) {
|
fn verror(s string) {
|
||||||
util.verror('parser error', s)
|
util.verror('parser error', s)
|
||||||
}
|
}
|
||||||
|
@ -1399,6 +1399,7 @@ fn (mut s Scanner) vet_error(msg string, fix vet.FixKind) {
|
|||||||
s.vet_errors << ve
|
s.vet_errors << ve
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[noreturn]
|
||||||
pub fn verror(s string) {
|
pub fn verror(s string) {
|
||||||
util.verror('scanner error', s)
|
util.verror('scanner error', s)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user