Skip to content

Commit aba5907

Browse files
committed
cgen: define perror
1 parent dbd3d2a commit aba5907

3 files changed

Lines changed: 93 additions & 1 deletion

File tree

vlib/v/gen/c/cheaders.v

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,7 @@ int sprintf(char *str, const char *format, ...);
418418
int sscanf(const char *str, const char *format, ...);
419419
int scanf(const char *format, ...);
420420
int puts(const char *str);
421+
void perror(const char *str);
421422
int fputs(const char *str, FILE *stream);
422423
int getchar(void);
423424
int putchar(int ch);
@@ -457,6 +458,7 @@ int remove(const char *path);
457458
int rename(const char *old_path, const char *new_path);
458459
char *realpath(const char *path, char *resolved_path);
459460
void qsort(void *base, size_t items, size_t item_size, qsort_callback_func cb);
461+
int strcmp(const char *left, const char *right);
460462
size_t strlen(const char *str);
461463
char *strerror(int errnum);
462464
void *memcpy(void *dest, const void *src, size_t n);

vlib/v/gen/c/cheaders_manual_stdlib_decls_test.v

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ fn test_default_c_prelude_uses_manual_stdio_stdlib_string_and_stdarg_decls() {
2828

2929
assert generated_c.contains('int vsnprintf(char *str, size_t size, const char *format, va_list ap);'), generated_c
3030

31+
assert generated_c.contains('void perror(const char *str);'), generated_c
32+
assert generated_c.contains('int strcmp(const char *left, const char *right);'), generated_c
3133
assert generated_c.contains('extern FILE* stdout;'), generated_c
3234
assert generated_c.contains('#define stdout (__acrt_iob_func(1))'), generated_c
3335
}
@@ -43,3 +45,19 @@ fn test_manual_stdio_decls_do_not_conflict_with_later_stdio_includes() {
4345
res := os.execute(cmd)
4446
assert res.exit_code == 0, '${cmd}\n${res.output}'
4547
}
48+
49+
fn test_manual_stdio_decls_allow_headerless_perror_declarations() {
50+
tmp_dir := os.join_path(os.vtmp_dir(), 'cheaders_manual_stdlib_perror_${os.getpid()}')
51+
os.mkdir_all(tmp_dir)!
52+
defer {
53+
os.rmdir_all(tmp_dir) or {}
54+
}
55+
source_path := os.join_path(tmp_dir, 'c_perror.v')
56+
os.write_file(source_path,
57+
58+
['fn C.perror(message &char)', '', 'fn main() {', "\tC.perror(c'')", '}'].join('\n') + '\n')!
59+
output_path := os.join_path(tmp_dir, 'c_perror')
60+
cmd := '${os.quoted_path(cheaders_manual_stdlib_vexe)} -o ${os.quoted_path(output_path)} ${os.quoted_path(source_path)}'
61+
res := os.execute(cmd)
62+
assert res.exit_code == 0, '${cmd}\n${res.output}'
63+
}

vlib/v/gen/c/fn.v

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,73 @@ import v.util
1212
// has[int, string]() => has_T_int_string()
1313
const c_fn_name_escape_seq = ['[', '_T_', ', ', '_', ']', '']
1414

15+
// c_manual_prelude_decl_names matches the C stdlib declarations emitted by `c_headers`.
16+
// When one of these symbols is declared in V as `fn C.name(...)`, cgen must not emit an
17+
// extra fallback prototype, or it can conflict with the prelude declaration.
18+
const c_manual_prelude_decl_names = [
19+
'vfprintf',
20+
'vsnprintf',
21+
'fprintf',
22+
'printf',
23+
'snprintf',
24+
'sprintf',
25+
'sscanf',
26+
'scanf',
27+
'puts',
28+
'perror',
29+
'fputs',
30+
'getchar',
31+
'putchar',
32+
'getc',
33+
'fgetc',
34+
'ungetc',
35+
'fflush',
36+
'feof',
37+
'ferror',
38+
'clearerr',
39+
'setvbuf',
40+
'ftell',
41+
'rewind',
42+
'fopen',
43+
'fdopen',
44+
'freopen',
45+
'fileno',
46+
'fread',
47+
'fwrite',
48+
'fgets',
49+
'fclose',
50+
'popen',
51+
'pclose',
52+
'malloc',
53+
'calloc',
54+
'realloc',
55+
'aligned_alloc',
56+
'free',
57+
'atexit',
58+
'exit',
59+
'atoi',
60+
'getenv',
61+
'setenv',
62+
'unsetenv',
63+
'system',
64+
'remove',
65+
'rename',
66+
'realpath',
67+
'qsort',
68+
'strcmp',
69+
'strlen',
70+
'strerror',
71+
'memcpy',
72+
'memmove',
73+
'memset',
74+
'memcmp',
75+
'memchr',
76+
'strchr',
77+
'strrchr',
78+
'fseek',
79+
'getline',
80+
]
81+
1582
fn collect_function_defer_stmts(node &ast.FnDecl) []ast.DeferStmt {
1683
mut defer_stmts := []ast.DeferStmt{}
1784
mut seen_idxs := []int{}
@@ -736,9 +803,14 @@ fn (g &Gen) module_has_c_header_module(file &ast.File) bool {
736803
return false
737804
}
738805

806+
fn (g &Gen) c_prelude_provides_decl(c_sym_name string) bool {
807+
return !g.pref.no_preludes && !g.pref.is_bare && c_sym_name in c_manual_prelude_decl_names
808+
}
809+
739810
fn (g &Gen) should_emit_c_fallback_decl(node ast.FnDecl) bool {
811+
c_sym_name := node.name.all_after_first('C__').all_after_first('C.')
740812
if node.language != .c || node.is_c_extern || file_has_c_includes(node.source_file)
741-
|| g.module_has_c_header_module(node.source_file) {
813+
|| g.module_has_c_header_module(node.source_file) || g.c_prelude_provides_decl(c_sym_name) {
742814
return false
743815
}
744816
if node.source_file == unsafe { nil } {

0 commit comments

Comments
 (0)