cgen,vfmt: support `[weak]` tags for functions and globals
parent
7fba3e65e9
commit
3caeadfa0d
|
@ -638,6 +638,7 @@ pub:
|
|||
mod string
|
||||
pos token.Position
|
||||
is_block bool // __global() block
|
||||
attrs []Attr
|
||||
pub mut:
|
||||
fields []GlobalField
|
||||
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) {
|
||||
f.attrs(node.attrs)
|
||||
if node.fields.len == 0 && node.pos.line_nr == node.pos.last_line {
|
||||
f.writeln('__global ()')
|
||||
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) {
|
||||
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 {
|
||||
if g.pref.skip_unused {
|
||||
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)
|
||||
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() {
|
||||
g.definitions.writeln(' = ${g.expr_string(field.expr)}; // global')
|
||||
} else {
|
||||
|
@ -5874,9 +5878,9 @@ fn (mut g Gen) global_decl(node ast.GlobalDecl) {
|
|||
} else {
|
||||
default_initializer := g.type_default(field.typ)
|
||||
if default_initializer == '{0}' {
|
||||
g.definitions.writeln('$mod$styp $field.name = {0}; // global')
|
||||
g.definitions.writeln('$mod$styp $attributes $field.name = {0}; // global')
|
||||
} 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'] {
|
||||
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
|
||||
#endif
|
||||
|
||||
|
||||
#if !defined(VWEAK)
|
||||
#define VWEAK __attribute__((weak))
|
||||
#ifdef _MSC_VER
|
||||
#undef VWEAK
|
||||
#define VWEAK
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(VNORETURN)
|
||||
#if defined(__TINYC__)
|
||||
#include <stdnoreturn.h>
|
||||
|
|
|
@ -105,19 +105,22 @@ fn test_c_must_have_files() ? {
|
|||
alloptions := '-o - $file_options.vflags'
|
||||
print(mm('v $alloptions $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)
|
||||
expected_lines := os.read_lines(must_have_path) or { [] }
|
||||
generated_c_lines := compilation.output.split_into_lines()
|
||||
mut nmatches := 0
|
||||
mut failed_patterns := []string{}
|
||||
for idx_expected_line, eline in expected_lines {
|
||||
if does_line_match_one_of_generated_lines(eline, generated_c_lines) {
|
||||
nmatches++
|
||||
// eprintln('> testing: $must_have_path has line: $eline')
|
||||
} else {
|
||||
failed_patterns << eline
|
||||
println(term.red('FAIL'))
|
||||
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))
|
||||
total_errors++
|
||||
continue
|
||||
|
@ -128,6 +131,11 @@ fn test_c_must_have_files() ? {
|
|||
} else {
|
||||
eprintln('> ALL lines:')
|
||||
eprintln(compilation.output)
|
||||
eprintln('--------- failed patterns: -------------------------------------------')
|
||||
for fpattern in failed_patterns {
|
||||
eprintln(fpattern)
|
||||
}
|
||||
eprintln('----------------------------------------------------------------------')
|
||||
}
|
||||
}
|
||||
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)
|
||||
msvc_attrs := g.write_fn_attrs(node.attrs)
|
||||
fn_attrs := g.write_fn_attrs(node.attrs)
|
||||
// Live
|
||||
is_livefn := node.attrs.contains('live')
|
||||
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 ')
|
||||
}
|
||||
}
|
||||
fn_header := if msvc_attrs.len > 0 {
|
||||
'$type_name $msvc_attrs ${name}('
|
||||
} else {
|
||||
'$type_name ${name}('
|
||||
}
|
||||
fn_header := '$type_name $fn_attrs${name}('
|
||||
g.definitions.write_string(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 {
|
||||
if attr.name == 'export' {
|
||||
g.writeln('// export alias: $attr.arg -> $name')
|
||||
calling_conv := if msvc_attrs.len > 0 { '$msvc_attrs ' } else { '' }
|
||||
export_alias := '$type_name $calling_conv${attr.arg}($arg_str)'
|
||||
export_alias := '$type_name $fn_attrs${attr.arg}($arg_str)'
|
||||
g.definitions.writeln('VV_EXPORTED_SYMBOL $export_alias; // exported fn $node.name')
|
||||
g.writeln('$export_alias {')
|
||||
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 {
|
||||
mut msvc_attrs := ''
|
||||
mut fn_attrs := ''
|
||||
for attr in attrs {
|
||||
match attr.name {
|
||||
'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.
|
||||
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' {
|
||||
// a `[noreturn]` tag tells the compiler, that a function
|
||||
// *DOES NOT RETURN* to its callsites.
|
||||
|
@ -1641,7 +1642,7 @@ fn (mut g Gen) write_fn_attrs(attrs []ast.Attr) string {
|
|||
'windows_stdcall' {
|
||||
// windows attributes (msvc/mingw)
|
||||
// prefixed by windows to indicate they're for advanced users only and not really supported by V.
|
||||
msvc_attrs += '__stdcall '
|
||||
fn_attrs += '__stdcall '
|
||||
}
|
||||
'console' {
|
||||
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`
|
||||
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
|
||||
&& !p.pref.is_livemain && !p.pref.building_v && !p.builtin_mod {
|
||||
p.error('use `v -enable-globals ...` to enable globals')
|
||||
|
@ -3173,6 +3178,7 @@ fn (mut p Parser) global_decl() ast.GlobalDecl {
|
|||
fields: fields
|
||||
end_comments: comments
|
||||
is_block: is_block
|
||||
attrs: attrs
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue