From e9177faf17dbd50f9c035378dff018a24b52f894 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Mon, 11 May 2020 16:05:59 +0200 Subject: [PATCH] checker: allow `*x = y` only inside unsafe blocks --- vlib/rand/rand.v | 4 +++- vlib/v/checker/checker.v | 11 +++++++++++ vlib/v/parser/parser.v | 26 +++++++++++++++----------- vlib/v/parser/pratt.v | 3 +++ 4 files changed, 32 insertions(+), 12 deletions(-) diff --git a/vlib/rand/rand.v b/vlib/rand/rand.v index 9ccd681b40..bc563c84ba 100644 --- a/vlib/rand/rand.v +++ b/vlib/rand/rand.v @@ -18,6 +18,8 @@ pub fn next(max int) int { // writes a result value to the seed argument. pub fn rand_r(seed &int) int { ns := *seed * 1103515245 + 12345 - (*seed) = ns + unsafe { + (*seed) = ns + } return ns & 0x7fffffff } diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 035026f913..617ce43bfa 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -38,6 +38,7 @@ pub mut: scope_returns bool mod string // current module name is_builtin_mod bool // are we in `builtin`? + inside_unsafe bool } pub fn new_checker(table &table.Table, pref &pref.Preferences) Checker { @@ -571,6 +572,14 @@ fn (mut c Checker) assign_expr(mut assign_expr ast.AssignExpr) { } // Make sure the variable is mutable c.fail_if_immutable(assign_expr.left) + // Do now allow `*x = y` outside `unsafe` + if assign_expr.left is ast.PrefixExpr { + p := assign_expr.left as ast.PrefixExpr + if p.op == .mul && !c.inside_unsafe { + c.error('modifying variables via deferencing can only be done in `unsafe` blocks', + assign_expr.pos) + } + } // Single side check match assign_expr.op { .assign {} // No need to do single side check for =. But here put it first for speed. @@ -1550,7 +1559,9 @@ fn (mut c Checker) stmt(node ast.Stmt) { c.type_decl(it) } ast.UnsafeStmt { + c.inside_unsafe = true c.stmts(it.stmts) + c.inside_unsafe = false } else { // println('checker.stmt(): unhandled node') diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 4e4babf179..497211fe02 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -44,6 +44,7 @@ mut: returns bool inside_match bool // to separate `match A { }` from `Struct{}` inside_match_case bool // to separate `match_expr { }` from `Struct{}` + inside_unsafe bool is_stmt_ident bool // true while the beginning of a statement is an ident/selector expecting_type bool // `is Type`, expecting type errors []errors.Error @@ -84,8 +85,8 @@ pub fn parse_file(path string, b_table &table.Table, comments_mode scanner.Comme start_pos: 0 parent: 0 } - errors: []errors.Error{}, - warnings: []errors.Warning{}, + errors: []errors.Error{} + warnings: []errors.Warning{} global_scope: global_scope } // comments_mode: comments_mode @@ -128,8 +129,8 @@ pub fn parse_file(path string, b_table &table.Table, comments_mode scanner.Comme imports: p.ast_imports stmts: stmts scope: p.scope - global_scope: p.global_scope, - errors: p.errors, + global_scope: p.global_scope + errors: p.errors warnings: p.warnings } } @@ -326,7 +327,8 @@ pub fn (mut p Parser) top_stmt() ast.Stmt { return p.interface_decl() } .key_import { - p.error_with_pos('`import x` can only be declared at the beginning of the file', p.tok.position()) + p.error_with_pos('`import x` can only be declared at the beginning of the file', + p.tok.position()) return p.import_stmt() } .key_global { @@ -433,7 +435,9 @@ pub fn (mut p Parser) stmt() ast.Stmt { } .key_unsafe { p.next() + p.inside_unsafe = true stmts := p.parse_block() + p.inside_unsafe = false return ast.UnsafeStmt{ stmts: stmts } @@ -580,9 +584,9 @@ pub fn (mut p Parser) error_with_pos(s string, pos token.Position) { exit(1) } else { p.errors << errors.Error{ - file_path: p.file_name, - pos: pos, - reporter: .parser, + file_path: p.file_name + pos: pos + reporter: .parser message: s } } @@ -594,9 +598,9 @@ pub fn (mut p Parser) warn_with_pos(s string, pos token.Position) { eprintln(ferror) } else { p.warnings << errors.Warning{ - file_path: p.file_name, - pos: pos, - reporter: .parser, + file_path: p.file_name + pos: pos + reporter: .parser message: s } } diff --git a/vlib/v/parser/pratt.v b/vlib/v/parser/pratt.v index 5e2e30a983..abcbfc1406 100644 --- a/vlib/v/parser/pratt.v +++ b/vlib/v/parser/pratt.v @@ -212,6 +212,9 @@ fn (mut p Parser) prefix_expr() ast.PrefixExpr { if op == .amp { p.is_amp = true } + // if op == .mul && !p.inside_unsafe { + // p.warn('unsafe') + // } p.next() right := p.expr(token.Precedence.prefix) p.is_amp = false