checker: check number of C function arguments for some cases (#8444)

pull/8454/head
Nick Treleaven 2021-01-30 17:33:36 +00:00 committed by GitHub
parent 2cadb3e4d8
commit 64d12cdc8d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 65 additions and 15 deletions

View File

@ -7,7 +7,7 @@ fn C.memcmp(byteptr, byteptr, int) int
fn C.memmove(byteptr, byteptr, int) voidptr fn C.memmove(byteptr, byteptr, int) voidptr
fn C.calloc(int) byteptr fn C.calloc(int, int) byteptr
fn C.malloc(int) byteptr fn C.malloc(int) byteptr
@ -48,16 +48,16 @@ fn C.printf(byteptr, ...byteptr) int
fn C.puts(byteptr) int fn C.puts(byteptr) int
fn C.fputs(byteptr) int fn C.fputs(str byteptr, stream &C.FILE) int
fn C.fflush(byteptr) int fn C.fflush(&C.FILE) int
// TODO define args in these functions // TODO define args in these functions
fn C.fseek() int fn C.fseek() int
fn C.fopen() voidptr fn C.fopen(filename charptr, mode charptr) &C.FILE
fn C.fileno(voidptr) int fn C.fileno(&C.FILE) int
fn C.fread(ptr voidptr, item_size size_t, items size_t, stream &C.FILE) size_t fn C.fread(ptr voidptr, item_size size_t, items size_t, stream &C.FILE) size_t
@ -86,7 +86,7 @@ fn C.waitpid(pid int, status &int, options int) int
fn C.kill(pid int, sig int) int fn C.kill(pid int, sig int) int
fn C.setenv(charptr) int fn C.setenv(charptr, charptr, int) int
fn C.unsetenv(charptr) int fn C.unsetenv(charptr) int
@ -100,7 +100,7 @@ fn C.chdir() int
fn C.rewind() int fn C.rewind() int
fn C.stat(charptr) int fn C.stat(charptr, voidptr) int
fn C.lstat() int fn C.lstat() int
@ -125,7 +125,7 @@ fn C.sleep(int) int
fn C.usleep() int fn C.usleep() int
fn C.opendir() voidptr fn C.opendir(charptr) voidptr
fn C.closedir() int fn C.closedir() int

View File

@ -105,22 +105,22 @@ fn decode_string(root &C.cJSON) string {
return tos_clone(root.valuestring) // , _strlen(root.valuestring)) return tos_clone(root.valuestring) // , _strlen(root.valuestring))
} }
fn C.cJSON_IsTrue() bool fn C.cJSON_IsTrue(voidptr) bool
fn C.cJSON_CreateNumber() &C.cJSON fn C.cJSON_CreateNumber(int) &C.cJSON
fn C.cJSON_CreateBool() &C.cJSON fn C.cJSON_CreateBool(bool) &C.cJSON
fn C.cJSON_CreateString() &C.cJSON fn C.cJSON_CreateString(charptr) &C.cJSON
fn C.cJSON_Parse() &C.cJSON fn C.cJSON_Parse(charptr) &C.cJSON
fn C.cJSON_PrintUnformatted() byteptr fn C.cJSON_PrintUnformatted(voidptr) byteptr
fn decode_bool(root &C.cJSON) bool { fn decode_bool(root &C.cJSON) bool {

View File

@ -16,7 +16,7 @@ fn C.ftell(fp voidptr) int
fn C.sigaction(int, voidptr, int) fn C.sigaction(int, voidptr, int)
fn C.open(charptr, int, int) int fn C.open(charptr, int, ...int) int
fn C.fdopen(int, string) voidptr fn C.fdopen(int, string) voidptr

View File

@ -1781,6 +1781,15 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type {
call_expr.should_be_skipped = true call_expr.should_be_skipped = true
} }
if f.language != .v || call_expr.language != .v { if f.language != .v || call_expr.language != .v {
// ignore C function of type `fn()`, assume untyped
// For now don't check C functions that are variadic, underscored, capitalized
// or have no params and return int
if f.language == .c && f.params.len != call_expr.args.len && !f.is_variadic
&& f.name[2] != `_` && !f.name[2].is_capital()
&& (f.params.len != 0 || f.return_type !in [table.void_type, table.int_type]) {
// change to error later
c.warn('expected $f.params.len arguments, but got $call_expr.args.len', call_expr.pos)
}
for arg in call_expr.args { for arg in call_expr.args {
c.expr(arg.expr) c.expr(arg.expr)
} }

View File

@ -0,0 +1,27 @@
vlib/v/checker/tests/c_fn_surplus_args.vv:7:4: error: expected 1 arguments, but got 0
5 | fn main() {
6 | C.no(1) // allowed
7 | C.y1()
| ~~~~
8 | C.y1(1) // ok
9 | C.y1(1, 2)
vlib/v/checker/tests/c_fn_surplus_args.vv:9:4: error: expected 1 arguments, but got 2
7 | C.y1()
8 | C.y1(1) // ok
9 | C.y1(1, 2)
| ~~~~~~~~
10 | C.ret() // ok
11 | C.ret(1)
vlib/v/checker/tests/c_fn_surplus_args.vv:11:4: error: expected 0 arguments, but got 1
9 | C.y1(1, 2)
10 | C.ret() // ok
11 | C.ret(1)
| ~~~~~~
12 | // avoid cgen whilst warning, later above should error
13 | main()
vlib/v/checker/tests/c_fn_surplus_args.vv:13:2: error: the `main` function cannot be called in the program
11 | C.ret(1)
12 | // avoid cgen whilst warning, later above should error
13 | main()
| ~~~~~~
14 | }

View File

@ -0,0 +1,14 @@
fn C.no() // untyped
fn C.y1(int)
fn C.ret()byte
fn main() {
C.no(1) // allowed
C.y1()
C.y1(1) // ok
C.y1(1, 2)
C.ret() // ok
C.ret(1)
// avoid cgen whilst warning, later above should error
main()
}