cgen,vfmt: support `[weak]` tags for functions and globals
parent
7fba3e65e9
commit
3caeadfa0d
|
@ -638,6 +638,7 @@ pub:
|
||||||
mod string
|
mod string
|
||||||
pos token.Position
|
pos token.Position
|
||||||
is_block bool // __global() block
|
is_block bool // __global() block
|
||||||
|
attrs []Attr
|
||||||
pub mut:
|
pub mut:
|
||||||
fields []GlobalField
|
fields []GlobalField
|
||||||
end_comments []Comment
|
end_comments []Comment
|
||||||
|
|
|
@ -1002,6 +1002,7 @@ pub fn (mut f Fmt) for_stmt(node ast.ForStmt) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut f Fmt) global_decl(node ast.GlobalDecl) {
|
pub fn (mut f Fmt) global_decl(node ast.GlobalDecl) {
|
||||||
|
f.attrs(node.attrs)
|
||||||
if node.fields.len == 0 && node.pos.line_nr == node.pos.last_line {
|
if node.fields.len == 0 && node.pos.line_nr == node.pos.last_line {
|
||||||
f.writeln('__global ()')
|
f.writeln('__global ()')
|
||||||
return
|
return
|
||||||
|
|
|
@ -5853,6 +5853,10 @@ fn (mut g Gen) const_decl_init_later(mod string, name string, expr ast.Expr, typ
|
||||||
|
|
||||||
fn (mut g Gen) global_decl(node ast.GlobalDecl) {
|
fn (mut g Gen) global_decl(node ast.GlobalDecl) {
|
||||||
mod := if g.pref.build_mode == .build_module && g.is_builtin_mod { 'static ' } else { '' }
|
mod := if g.pref.build_mode == .build_module && g.is_builtin_mod { 'static ' } else { '' }
|
||||||
|
mut attributes := ''
|
||||||
|
if node.attrs.contains('weak') {
|
||||||
|
attributes += 'VWEAK '
|
||||||
|
}
|
||||||
for field in node.fields {
|
for field in node.fields {
|
||||||
if g.pref.skip_unused {
|
if g.pref.skip_unused {
|
||||||
if field.name !in g.table.used_globals {
|
if field.name !in g.table.used_globals {
|
||||||
|
@ -5864,7 +5868,7 @@ fn (mut g Gen) global_decl(node ast.GlobalDecl) {
|
||||||
}
|
}
|
||||||
styp := g.typ(field.typ)
|
styp := g.typ(field.typ)
|
||||||
if field.has_expr {
|
if field.has_expr {
|
||||||
g.definitions.write_string('$mod$styp $field.name')
|
g.definitions.write_string('$mod$styp $attributes $field.name')
|
||||||
if field.expr.is_literal() {
|
if field.expr.is_literal() {
|
||||||
g.definitions.writeln(' = ${g.expr_string(field.expr)}; // global')
|
g.definitions.writeln(' = ${g.expr_string(field.expr)}; // global')
|
||||||
} else {
|
} else {
|
||||||
|
@ -5874,9 +5878,9 @@ fn (mut g Gen) global_decl(node ast.GlobalDecl) {
|
||||||
} else {
|
} else {
|
||||||
default_initializer := g.type_default(field.typ)
|
default_initializer := g.type_default(field.typ)
|
||||||
if default_initializer == '{0}' {
|
if default_initializer == '{0}' {
|
||||||
g.definitions.writeln('$mod$styp $field.name = {0}; // global')
|
g.definitions.writeln('$mod$styp $attributes $field.name = {0}; // global')
|
||||||
} else {
|
} else {
|
||||||
g.definitions.writeln('$mod$styp $field.name; // global')
|
g.definitions.writeln('$mod$styp $attributes $field.name; // global')
|
||||||
if field.name !in ['as_cast_type_indexes', 'g_memory_block'] {
|
if field.name !in ['as_cast_type_indexes', 'g_memory_block'] {
|
||||||
g.global_init.writeln('\t$field.name = *($styp*)&(($styp[]){${g.type_default(field.typ)}}[0]); // global')
|
g.global_init.writeln('\t$field.name = *($styp*)&(($styp[]){${g.type_default(field.typ)}}[0]); // global')
|
||||||
}
|
}
|
||||||
|
|
|
@ -254,6 +254,15 @@ const c_common_macros = '
|
||||||
#undef __has_include
|
#undef __has_include
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if !defined(VWEAK)
|
||||||
|
#define VWEAK __attribute__((weak))
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#undef VWEAK
|
||||||
|
#define VWEAK
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#if !defined(VNORETURN)
|
#if !defined(VNORETURN)
|
||||||
#if defined(__TINYC__)
|
#if defined(__TINYC__)
|
||||||
#include <stdnoreturn.h>
|
#include <stdnoreturn.h>
|
||||||
|
|
|
@ -105,19 +105,22 @@ fn test_c_must_have_files() ? {
|
||||||
alloptions := '-o - $file_options.vflags'
|
alloptions := '-o - $file_options.vflags'
|
||||||
print(mm('v $alloptions $relpath') +
|
print(mm('v $alloptions $relpath') +
|
||||||
' matches all line patterns in ${mm(must_have_relpath)} ')
|
' matches all line patterns in ${mm(must_have_relpath)} ')
|
||||||
compilation := os.execute('$vexe $alloptions $path')
|
cmd := '$vexe $alloptions $path'
|
||||||
|
compilation := os.execute(cmd)
|
||||||
ensure_compilation_succeeded(compilation)
|
ensure_compilation_succeeded(compilation)
|
||||||
expected_lines := os.read_lines(must_have_path) or { [] }
|
expected_lines := os.read_lines(must_have_path) or { [] }
|
||||||
generated_c_lines := compilation.output.split_into_lines()
|
generated_c_lines := compilation.output.split_into_lines()
|
||||||
mut nmatches := 0
|
mut nmatches := 0
|
||||||
|
mut failed_patterns := []string{}
|
||||||
for idx_expected_line, eline in expected_lines {
|
for idx_expected_line, eline in expected_lines {
|
||||||
if does_line_match_one_of_generated_lines(eline, generated_c_lines) {
|
if does_line_match_one_of_generated_lines(eline, generated_c_lines) {
|
||||||
nmatches++
|
nmatches++
|
||||||
// eprintln('> testing: $must_have_path has line: $eline')
|
// eprintln('> testing: $must_have_path has line: $eline')
|
||||||
} else {
|
} else {
|
||||||
|
failed_patterns << eline
|
||||||
println(term.red('FAIL'))
|
println(term.red('FAIL'))
|
||||||
eprintln('$must_have_path:${idx_expected_line + 1}: expected match error:')
|
eprintln('$must_have_path:${idx_expected_line + 1}: expected match error:')
|
||||||
eprintln('`$vexe -o - $path` does NOT produce expected line:')
|
eprintln('`$cmd` did NOT produce expected line:')
|
||||||
eprintln(term.colorize(term.red, eline))
|
eprintln(term.colorize(term.red, eline))
|
||||||
total_errors++
|
total_errors++
|
||||||
continue
|
continue
|
||||||
|
@ -128,6 +131,11 @@ fn test_c_must_have_files() ? {
|
||||||
} else {
|
} else {
|
||||||
eprintln('> ALL lines:')
|
eprintln('> ALL lines:')
|
||||||
eprintln(compilation.output)
|
eprintln(compilation.output)
|
||||||
|
eprintln('--------- failed patterns: -------------------------------------------')
|
||||||
|
for fpattern in failed_patterns {
|
||||||
|
eprintln(fpattern)
|
||||||
|
}
|
||||||
|
eprintln('----------------------------------------------------------------------')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert total_errors == 0
|
assert total_errors == 0
|
||||||
|
|
|
@ -187,7 +187,7 @@ fn (mut g Gen) gen_fn_decl(node &ast.FnDecl, skip bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
g.write_v_source_line_info(node.pos)
|
g.write_v_source_line_info(node.pos)
|
||||||
msvc_attrs := g.write_fn_attrs(node.attrs)
|
fn_attrs := g.write_fn_attrs(node.attrs)
|
||||||
// Live
|
// Live
|
||||||
is_livefn := node.attrs.contains('live')
|
is_livefn := node.attrs.contains('live')
|
||||||
is_livemain := g.pref.is_livemain && is_livefn
|
is_livemain := g.pref.is_livemain && is_livefn
|
||||||
|
@ -291,11 +291,7 @@ fn (mut g Gen) gen_fn_decl(node &ast.FnDecl, skip bool) {
|
||||||
g.definitions.write_string('VV_LOCAL_SYMBOL ')
|
g.definitions.write_string('VV_LOCAL_SYMBOL ')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn_header := if msvc_attrs.len > 0 {
|
fn_header := '$type_name $fn_attrs${name}('
|
||||||
'$type_name $msvc_attrs ${name}('
|
|
||||||
} else {
|
|
||||||
'$type_name ${name}('
|
|
||||||
}
|
|
||||||
g.definitions.write_string(fn_header)
|
g.definitions.write_string(fn_header)
|
||||||
g.write(fn_header)
|
g.write(fn_header)
|
||||||
}
|
}
|
||||||
|
@ -426,8 +422,7 @@ fn (mut g Gen) gen_fn_decl(node &ast.FnDecl, skip bool) {
|
||||||
for attr in node.attrs {
|
for attr in node.attrs {
|
||||||
if attr.name == 'export' {
|
if attr.name == 'export' {
|
||||||
g.writeln('// export alias: $attr.arg -> $name')
|
g.writeln('// export alias: $attr.arg -> $name')
|
||||||
calling_conv := if msvc_attrs.len > 0 { '$msvc_attrs ' } else { '' }
|
export_alias := '$type_name $fn_attrs${attr.arg}($arg_str)'
|
||||||
export_alias := '$type_name $calling_conv${attr.arg}($arg_str)'
|
|
||||||
g.definitions.writeln('VV_EXPORTED_SYMBOL $export_alias; // exported fn $node.name')
|
g.definitions.writeln('VV_EXPORTED_SYMBOL $export_alias; // exported fn $node.name')
|
||||||
g.writeln('$export_alias {')
|
g.writeln('$export_alias {')
|
||||||
g.write('\treturn ${name}(')
|
g.write('\treturn ${name}(')
|
||||||
|
@ -1565,7 +1560,7 @@ fn (g &Gen) fileis(s string) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) write_fn_attrs(attrs []ast.Attr) string {
|
fn (mut g Gen) write_fn_attrs(attrs []ast.Attr) string {
|
||||||
mut msvc_attrs := ''
|
mut fn_attrs := ''
|
||||||
for attr in attrs {
|
for attr in attrs {
|
||||||
match attr.name {
|
match attr.name {
|
||||||
'inline' {
|
'inline' {
|
||||||
|
@ -1575,6 +1570,12 @@ fn (mut g Gen) write_fn_attrs(attrs []ast.Attr) string {
|
||||||
// since these are supported by GCC, clang and MSVC, we can consider them officially supported.
|
// since these are supported by GCC, clang and MSVC, we can consider them officially supported.
|
||||||
g.write('__NOINLINE ')
|
g.write('__NOINLINE ')
|
||||||
}
|
}
|
||||||
|
'weak' {
|
||||||
|
// a `[weak]` tag tells the C compiler, that the next declaration will be weak, i.e. when linking,
|
||||||
|
// if there is another declaration of a symbol with the same name (a 'strong' one), it should be
|
||||||
|
// used instead, *without linker errors about duplicate symbols*.
|
||||||
|
g.write('VWEAK ')
|
||||||
|
}
|
||||||
'noreturn' {
|
'noreturn' {
|
||||||
// a `[noreturn]` tag tells the compiler, that a function
|
// a `[noreturn]` tag tells the compiler, that a function
|
||||||
// *DOES NOT RETURN* to its callsites.
|
// *DOES NOT RETURN* to its callsites.
|
||||||
|
@ -1641,7 +1642,7 @@ fn (mut g Gen) write_fn_attrs(attrs []ast.Attr) string {
|
||||||
'windows_stdcall' {
|
'windows_stdcall' {
|
||||||
// windows attributes (msvc/mingw)
|
// windows attributes (msvc/mingw)
|
||||||
// prefixed by windows to indicate they're for advanced users only and not really supported by V.
|
// prefixed by windows to indicate they're for advanced users only and not really supported by V.
|
||||||
msvc_attrs += '__stdcall '
|
fn_attrs += '__stdcall '
|
||||||
}
|
}
|
||||||
'console' {
|
'console' {
|
||||||
g.force_main_console = true
|
g.force_main_console = true
|
||||||
|
@ -1651,5 +1652,5 @@ fn (mut g Gen) write_fn_attrs(attrs []ast.Attr) string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return msvc_attrs
|
return fn_attrs
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
u64 VWEAK abc = ((u64)(1U)); // global
|
||||||
|
u64 xyz = ((u64)(2U)); // global
|
||||||
|
u64 VWEAK weak_1 = ((u64)(4U)); // global
|
||||||
|
u64 VWEAK weak_2 = ((u64)(5U)); // global
|
||||||
|
VV_LOCAL_SYMBOL int main__a_weak_function(void);
|
||||||
|
VV_LOCAL_SYMBOL void main__main(void);
|
||||||
|
|
||||||
|
VWEAK VV_LOCAL_SYMBOL int main__a_weak_function(void) {
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
// vtest vflags: -enable-globals
|
||||||
|
|
||||||
|
[weak]
|
||||||
|
__global abc = u64(1)
|
||||||
|
__global xyz = u64(2)
|
||||||
|
|
||||||
|
[weak]
|
||||||
|
__global (
|
||||||
|
weak_1 = u64(4)
|
||||||
|
weak_2 = u64(5)
|
||||||
|
)
|
||||||
|
|
||||||
|
[weak]
|
||||||
|
fn a_weak_function() int {
|
||||||
|
return 42
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
println('abc: $abc')
|
||||||
|
println('xyz: $xyz')
|
||||||
|
println('xyz: $xyz')
|
||||||
|
println('weak_1: $weak_1')
|
||||||
|
println('weak_2: $weak_2')
|
||||||
|
println(a_weak_function())
|
||||||
|
}
|
|
@ -3081,6 +3081,11 @@ fn (mut p Parser) return_stmt() ast.Return {
|
||||||
|
|
||||||
// left hand side of `=` or `:=` in `a,b,c := 1,2,3`
|
// left hand side of `=` or `:=` in `a,b,c := 1,2,3`
|
||||||
fn (mut p Parser) global_decl() ast.GlobalDecl {
|
fn (mut p Parser) global_decl() ast.GlobalDecl {
|
||||||
|
mut attrs := []ast.Attr{}
|
||||||
|
if p.attrs.len > 0 {
|
||||||
|
attrs = p.attrs
|
||||||
|
p.attrs = []
|
||||||
|
}
|
||||||
if !p.has_globals && !p.pref.enable_globals && !p.pref.is_fmt && !p.pref.translated
|
if !p.has_globals && !p.pref.enable_globals && !p.pref.is_fmt && !p.pref.translated
|
||||||
&& !p.pref.is_livemain && !p.pref.building_v && !p.builtin_mod {
|
&& !p.pref.is_livemain && !p.pref.building_v && !p.builtin_mod {
|
||||||
p.error('use `v -enable-globals ...` to enable globals')
|
p.error('use `v -enable-globals ...` to enable globals')
|
||||||
|
@ -3173,6 +3178,7 @@ fn (mut p Parser) global_decl() ast.GlobalDecl {
|
||||||
fields: fields
|
fields: fields
|
||||||
end_comments: comments
|
end_comments: comments
|
||||||
is_block: is_block
|
is_block: is_block
|
||||||
|
attrs: attrs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue