From 049d78a78dd4be7ccecc31a0b8bbfa53135d1526 Mon Sep 17 00:00:00 2001 From: Emily Hudson Date: Wed, 24 Jul 2019 16:46:41 +0100 Subject: [PATCH] Change CGen so that v.c is compileable with msvc --- compiler/fn.v | 4 ++-- compiler/main.v | 13 +++++++++++++ compiler/parser.v | 37 +++++++++++++------------------------ compiler/table.v | 4 ++-- 4 files changed, 30 insertions(+), 28 deletions(-) diff --git a/compiler/fn.v b/compiler/fn.v index 33412c7527..479113bea7 100644 --- a/compiler/fn.v +++ b/compiler/fn.v @@ -493,9 +493,9 @@ fn (p mut Parser) async_fn_call(f Fn, method_ph int, receiver_var, receiver_type did_gen_something = true } - if p.os == .msvc && !did_gen_something { + if !did_gen_something { // Msvc doesnt like empty struct - arg_struct += 'void *____dummy_variable;' + arg_struct += 'EMPTY_STRUCT_DECLARATION' } arg_struct += '} $arg_struct_name ;' diff --git a/compiler/main.v b/compiler/main.v index 6b5f9e4b53..dbb646f124 100644 --- a/compiler/main.v +++ b/compiler/main.v @@ -189,6 +189,10 @@ fn (v mut V) compile() { #include // for va_list #include // int64_t etc +#define STRUCT_DEFAULT_VALUE {} +#define EMPTY_STRUCT_DECLARATION +#define EMPTY_STRUCT_INIT +#define OPTION_CAST(x) (x) #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN @@ -201,6 +205,15 @@ fn (v mut V) compile() { #ifdef _MSC_VER // On MSVC these are the same (as long as /volatile:ms is passed) #define _Atomic volatile + +// MSVC can\'t parse some things properly +#undef STRUCT_DEFAULT_VALUE +#define STRUCT_DEFAULT_VALUE {0} +#undef EMPTY_STRUCT_DECLARATION +#define EMPTY_STRUCT_DECLARATION void *____dummy_variable; +#undef EMPTY_STRUCT_INIT +#define EMPTY_STRUCT_INIT 0 +#define OPTION_CAST(x) #endif void pthread_mutex_lock(HANDLE *m) { diff --git a/compiler/parser.v b/compiler/parser.v index 941cf42b26..82000374d0 100644 --- a/compiler/parser.v +++ b/compiler/parser.v @@ -618,8 +618,8 @@ fn (p mut Parser) struct_decl() { p.check(.rcbr) if !is_c { - if p.os == .msvc && !did_gen_something { - p.gen_type('void *____dummy_variable; };') + if !did_gen_something { + p.gen_type('EMPTY_STRUCT_DECLARATION };') p.fgenln('') } else { p.gen_type('}; ') @@ -1895,7 +1895,7 @@ fn (p mut Parser) index_expr(typ string, fn_ph int) string { if is_map { p.gen('$tmp') mut def := type_default(typ) - if p.os == .msvc && def == '{}' { + if def == 'STRUCT_DEFAULT_VALUE' { def = '{0}' } p.cgen.insert_before('$typ $tmp = $def; bool $tmp_ok = map_get($index_expr, & $tmp);') @@ -2025,7 +2025,7 @@ fn (p mut Parser) expression() string { } // 3 + 4 else if is_num { - if p.os == .msvc && typ == 'void*' { + if typ == 'void*' { // Msvc errors on void* pointer arithmatic // ... So cast to byte* and then do the add p.cgen.set_placeholder(ph, '(byte*)') @@ -2467,11 +2467,7 @@ fn (p mut Parser) array_init() string { name := p.check_name() if p.table.known_type(name) { p.cgen.resetln('') - if p.os == .msvc { - p.gen('{0}') - } else { - p.gen('{}') - } + p.gen('STRUCT_DEFAULT_VALUE') return '[$lit]$name' } else { @@ -2555,8 +2551,8 @@ fn (p mut Parser) array_init() string { // p.gen('$new_arr($vals.len, $vals.len, sizeof($typ), ($typ[]) $c_arr );') // TODO why need !first_run()?? Otherwise it goes to the very top of the out.c file if !p.first_run() { - if p.os == .msvc && i == 0 { - p.cgen.set_placeholder(new_arr_ph, '$new_arr($i, $i, sizeof($typ), ($typ[]) {0 ') + if i == 0 { + p.cgen.set_placeholder(new_arr_ph, '$new_arr($i, $i, sizeof($typ), ($typ[]) {EMPTY_STRUCT_INIT ') } else { p.cgen.set_placeholder(new_arr_ph, '$new_arr($i, $i, sizeof($typ), ($typ[]) { ') } @@ -2666,7 +2662,7 @@ fn (p mut Parser) struct_init(is_c_struct_init bool) string { p.error('pointer field `${typ}.${field.name}` must be initialized') } def_val := type_default(field_typ) - if def_val != '' && def_val != '{}' { + if def_val != '' && def_val != 'STRUCT_DEFAULT_VALUE' { p.gen('.$field.name = $def_val') if i != t.fields.len - 1 { p.gen(',') @@ -2706,8 +2702,8 @@ fn (p mut Parser) struct_init(is_c_struct_init bool) string { did_gen_something = true } - if p.os == .msvc && !did_gen_something { - p.gen('0') + if !did_gen_something { + p.gen('EMPTY_STRUCT_INIT') } p.gen('}') @@ -3108,7 +3104,7 @@ fn (p mut Parser) for_st() { p.genln(' string $i = ((string*)keys_$tmp .data)[l];') //p.genln(' string $i = *(string*) ( array__get(keys_$tmp, l) );') mut def := type_default(typ) - if def == '{}' { + if def == 'STRUCT_DEFAULT_VALUE' { def = '{0}' } // TODO don't call map_get() for each key, fetch values while traversing @@ -3293,15 +3289,8 @@ fn (p mut Parser) return_st() { tmp := p.get_tmp() ret := p.cgen.cur_line.right(ph) - if p.os != .msvc { - p.cgen.cur_line = '$expr_type $tmp = ($expr_type)($ret);' - p.cgen.resetln('$expr_type $tmp = ($expr_type)($ret);') - } else { - // Both the return type and the expression type have already been concluded - // to be the same - the cast is slightly pointless - // and msvc cant do it - p.cgen.resetln('$expr_type $tmp = ($ret);') - } + p.cgen.cur_line = '$expr_type $tmp = OPTION_CAST($expr_type)($ret);' + p.cgen.resetln('$expr_type $tmp = OPTION_CAST($expr_type)($ret);') p.gen('return opt_ok(&$tmp, sizeof($expr_type))') } else { diff --git a/compiler/table.v b/compiler/table.v index f9af85d42e..1d76f6835c 100644 --- a/compiler/table.v +++ b/compiler/table.v @@ -544,7 +544,7 @@ fn type_default(typ string) string { } // User struct defined in another module. if typ.contains('__') { - return '{}' + return 'STRUCT_DEFAULT_VALUE' } // Default values for other types are not needed because of mandatory initialization switch typ { @@ -566,7 +566,7 @@ fn type_default(typ string) string { case 'byteptr': return '0' case 'voidptr': return '0' } - return '{}' + return 'STRUCT_DEFAULT_VALUE' } // TODO PERF O(n)