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() {
|
||||
unsafe {
|
||||
mut ptr := &voidptr(0)
|
||||
*ptr = 0
|
||||
*ptr = voidptr(0)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -234,7 +234,7 @@ fn break_if_debugger_attached() {
|
|||
$if tinyc {
|
||||
unsafe {
|
||||
mut ptr := &voidptr(0)
|
||||
*ptr = 0
|
||||
*ptr = voidptr(0)
|
||||
}
|
||||
} $else {
|
||||
if C.IsDebuggerPresent() {
|
||||
|
|
|
@ -425,9 +425,7 @@ fn (cb &Clipboard) get_supported_targets() []C.Atom {
|
|||
}
|
||||
|
||||
fn new_atom(value int) &C.Atom {
|
||||
mut atom := &C.Atom{}
|
||||
atom = value
|
||||
return atom
|
||||
return unsafe {&C.Atom(value)}
|
||||
}
|
||||
|
||||
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) {
|
||||
if r.live_lib != 0 {
|
||||
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)
|
||||
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) {
|
||||
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)
|
||||
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 {
|
||||
|
|
|
@ -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)
|
||||
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 {
|
||||
// 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
|
||||
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)
|
||||
mut rtype := right_type_unwrapped
|
||||
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)
|
||||
c.error('mismatched types `$left_name` and `$right_name`', assign_stmt.pos)
|
||||
}
|
||||
}
|
||||
// Single side check
|
||||
match assign_stmt.op {
|
||||
.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.name == 'C.NULL' {
|
||||
return table.voidptr_type
|
||||
}
|
||||
return table.int_type
|
||||
}
|
||||
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() {
|
||||
g.ns = 0
|
||||
g.ns = &Namespace(0)
|
||||
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.h(&int)
|
||||
fn JS.i(...string)
|
||||
|
||||
fn test_null() {
|
||||
np := C.NULL
|
||||
assert typeof(np).name == 'voidptr'
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue