checker: disallow assigning number to pointer (#7267)
parent
5fec0d785a
commit
d785e22a6e
|
@ -140,6 +140,6 @@ fn print_backtrace_skipping_top_frames_linux(skipframes int) bool {
|
||||||
fn break_if_debugger_attached() {
|
fn break_if_debugger_attached() {
|
||||||
unsafe {
|
unsafe {
|
||||||
mut ptr := &voidptr(0)
|
mut ptr := &voidptr(0)
|
||||||
*ptr = 0
|
*ptr = voidptr(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -234,7 +234,7 @@ fn break_if_debugger_attached() {
|
||||||
$if tinyc {
|
$if tinyc {
|
||||||
unsafe {
|
unsafe {
|
||||||
mut ptr := &voidptr(0)
|
mut ptr := &voidptr(0)
|
||||||
*ptr = 0
|
*ptr = voidptr(0)
|
||||||
}
|
}
|
||||||
} $else {
|
} $else {
|
||||||
if C.IsDebuggerPresent() {
|
if C.IsDebuggerPresent() {
|
||||||
|
|
|
@ -425,9 +425,7 @@ fn (cb &Clipboard) get_supported_targets() []C.Atom {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_atom(value int) &C.Atom {
|
fn new_atom(value int) &C.Atom {
|
||||||
mut atom := &C.Atom{}
|
return unsafe {&C.Atom(value)}
|
||||||
atom = value
|
|
||||||
return atom
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_xwindow(display &C.Display) C.Window {
|
fn create_xwindow(display &C.Display) C.Window {
|
||||||
|
|
|
@ -118,7 +118,7 @@ fn load_lib(mut r live.LiveReloadInfo, new_lib_path string) {
|
||||||
fn protected_load_lib(mut r live.LiveReloadInfo, new_lib_path string) {
|
fn protected_load_lib(mut r live.LiveReloadInfo, new_lib_path string) {
|
||||||
if r.live_lib != 0 {
|
if r.live_lib != 0 {
|
||||||
dl.close( r.live_lib )
|
dl.close( r.live_lib )
|
||||||
r.live_lib = 0
|
r.live_lib = C.NULL
|
||||||
}
|
}
|
||||||
r.live_lib = dl.open(new_lib_path, dl.rtld_lazy)
|
r.live_lib = dl.open(new_lib_path, dl.rtld_lazy)
|
||||||
if r.live_lib == 0 {
|
if r.live_lib == 0 {
|
||||||
|
|
|
@ -283,9 +283,14 @@ pub fn (mut c Checker) check_expected(got table.Type, expected table.Type) ? {
|
||||||
if c.check_types(got, expected) {
|
if c.check_types(got, expected) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
return error(c.expected_msg(got, expected))
|
||||||
|
}
|
||||||
|
|
||||||
|
[inline]
|
||||||
|
fn (c &Checker) expected_msg(got table.Type, expected table.Type) string {
|
||||||
exps := c.table.type_to_str(expected)
|
exps := c.table.type_to_str(expected)
|
||||||
gots := c.table.type_to_str(got)
|
gots := c.table.type_to_str(got)
|
||||||
return error('expected `$exps`, not `$gots`')
|
return 'expected `$exps`, not `$gots`'
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut c Checker) symmetric_check(left table.Type, right table.Type) bool {
|
pub fn (mut c Checker) symmetric_check(left table.Type, right table.Type) bool {
|
||||||
|
|
|
@ -2173,18 +2173,23 @@ pub fn (mut c Checker) assign_stmt(mut assign_stmt ast.AssignStmt) {
|
||||||
}
|
}
|
||||||
left_sym := c.table.get_type_symbol(left_type_unwrapped)
|
left_sym := c.table.get_type_symbol(left_type_unwrapped)
|
||||||
right_sym := c.table.get_type_symbol(right_type_unwrapped)
|
right_sym := c.table.get_type_symbol(right_type_unwrapped)
|
||||||
left_is_ptr := left_type.is_ptr() || left_sym.is_pointer()
|
|
||||||
right_is_ptr := right_type.is_ptr() || right_sym.is_pointer()
|
|
||||||
if left_is_ptr && assign_stmt.op !in [.assign, .decl_assign] && !c.inside_unsafe {
|
|
||||||
// ptr op=
|
|
||||||
c.warn('pointer arithmetic is only allowed in `unsafe` blocks', assign_stmt.pos)
|
|
||||||
}
|
|
||||||
if c.pref.translated {
|
if c.pref.translated {
|
||||||
// TODO fix this in C2V instead, for example cast enums to int before using `|` on them.
|
// TODO fix this in C2V instead, for example cast enums to int before using `|` on them.
|
||||||
// TODO replace all c.pref.translated checks with `$if !translated` for performance
|
// TODO replace all c.pref.translated checks with `$if !translated` for performance
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if left_is_ptr && (right is ast.StructInit || !right_is_ptr) && !right_sym.is_number() {
|
left_is_ptr := left_type.is_ptr() || left_sym.is_pointer()
|
||||||
|
if left_is_ptr {
|
||||||
|
if !c.inside_unsafe && assign_stmt.op !in [.assign, .decl_assign] {
|
||||||
|
// ptr op=
|
||||||
|
c.warn('pointer arithmetic is only allowed in `unsafe` blocks', assign_stmt.pos)
|
||||||
|
}
|
||||||
|
right_is_ptr := right_type.is_ptr() || right_sym.is_pointer()
|
||||||
|
if !right_is_ptr && assign_stmt.op == .assign && right_type_unwrapped.is_number() {
|
||||||
|
c.error('cannot assign to `$left`: ' +
|
||||||
|
c.expected_msg(right_type_unwrapped, left_type_unwrapped), right.position())
|
||||||
|
}
|
||||||
|
if (right is ast.StructInit || !right_is_ptr) && !right_sym.is_number() {
|
||||||
left_name := c.table.type_to_str(left_type_unwrapped)
|
left_name := c.table.type_to_str(left_type_unwrapped)
|
||||||
mut rtype := right_type_unwrapped
|
mut rtype := right_type_unwrapped
|
||||||
if rtype.is_ptr() {
|
if rtype.is_ptr() {
|
||||||
|
@ -2193,6 +2198,7 @@ pub fn (mut c Checker) assign_stmt(mut assign_stmt ast.AssignStmt) {
|
||||||
right_name := c.table.type_to_str(rtype)
|
right_name := c.table.type_to_str(rtype)
|
||||||
c.error('mismatched types `$left_name` and `$right_name`', assign_stmt.pos)
|
c.error('mismatched types `$left_name` and `$right_name`', assign_stmt.pos)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Single side check
|
// Single side check
|
||||||
match assign_stmt.op {
|
match assign_stmt.op {
|
||||||
.assign {} // No need to do single side check for =. But here put it first for speed.
|
.assign {} // No need to do single side check for =. But here put it first for speed.
|
||||||
|
@ -3364,6 +3370,9 @@ pub fn (mut c Checker) ident(mut ident ast.Ident) table.Type {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ident.language == .c {
|
if ident.language == .c {
|
||||||
|
if ident.name == 'C.NULL' {
|
||||||
|
return table.voidptr_type
|
||||||
|
}
|
||||||
return table.int_type
|
return table.int_type
|
||||||
}
|
}
|
||||||
if c.inside_sql {
|
if c.inside_sql {
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
vlib/v/checker/tests/ptr_assign.vv:3:5: error: cannot assign to `p`: expected `&int`, not `any_int`
|
||||||
|
1 | mut v := 43
|
||||||
|
2 | mut p := &v
|
||||||
|
3 | p = 4
|
||||||
|
| ^
|
|
@ -0,0 +1,3 @@
|
||||||
|
mut v := 43
|
||||||
|
mut p := &v
|
||||||
|
p = 4
|
|
@ -193,7 +193,7 @@ pub fn (mut g JsGen) enter_namespace(name string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut g JsGen) escape_namespace() {
|
pub fn (mut g JsGen) escape_namespace() {
|
||||||
g.ns = 0
|
g.ns = &Namespace(0)
|
||||||
g.inside_builtin = false
|
g.inside_builtin = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,3 +14,8 @@ fn JS.f(a &Foo) // TODO: Should this be allowed?
|
||||||
fn C.g(string, ...int)
|
fn C.g(string, ...int)
|
||||||
fn C.h(&int)
|
fn C.h(&int)
|
||||||
fn JS.i(...string)
|
fn JS.i(...string)
|
||||||
|
|
||||||
|
fn test_null() {
|
||||||
|
np := C.NULL
|
||||||
|
assert typeof(np).name == 'voidptr'
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue