cgen: properly handle initialization expression for globals (#10981)

pull/10984/head
Uwe Krüger 2021-07-28 07:11:55 +02:00 committed by GitHub
parent 61ed1d810f
commit 45ad48d76a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 60 additions and 17 deletions

View File

@ -535,11 +535,11 @@ pub:
pub struct GlobalField { pub struct GlobalField {
pub: pub:
name string name string
expr Expr
has_expr bool has_expr bool
pos token.Position pos token.Position
typ_pos token.Position typ_pos token.Position
pub mut: pub mut:
expr Expr
typ Type typ Type
comments []Comment comments []Comment
} }

View File

@ -26,6 +26,7 @@ pub mut:
is_fmt bool is_fmt bool
used_fns map[string]bool // filled in by the checker, when pref.skip_unused = true; used_fns map[string]bool // filled in by the checker, when pref.skip_unused = true;
used_consts map[string]bool // filled in by the checker, when pref.skip_unused = true; used_consts map[string]bool // filled in by the checker, when pref.skip_unused = true;
used_globals map[string]bool // filled in by the checker, when pref.skip_unused = true;
used_vweb_types []Type // vweb context types, filled in by checker, when pref.skip_unused = true; used_vweb_types []Type // vweb context types, filled in by checker, when pref.skip_unused = true;
used_maps int // how many times maps were used, filled in by checker, when pref.skip_unused = true; used_maps int // how many times maps were used, filled in by checker, when pref.skip_unused = true;
panic_handler FnPanicHandler = default_table_panic_handler panic_handler FnPanicHandler = default_table_panic_handler
@ -52,6 +53,7 @@ pub fn (t &Table) free() {
t.cmod_prefix.free() t.cmod_prefix.free()
t.used_fns.free() t.used_fns.free()
t.used_consts.free() t.used_consts.free()
t.used_globals.free()
t.used_vweb_types.free() t.used_vweb_types.free()
} }
} }

View File

@ -4544,7 +4544,7 @@ fn (mut c Checker) stmt(node ast.Stmt) {
c.for_stmt(mut node) c.for_stmt(mut node)
} }
ast.GlobalDecl { ast.GlobalDecl {
c.global_decl(node) c.global_decl(mut node)
} }
ast.GotoLabel {} ast.GotoLabel {}
ast.GotoStmt { ast.GotoStmt {
@ -4793,8 +4793,8 @@ fn (mut c Checker) for_stmt(mut node ast.ForStmt) {
c.in_for_count-- c.in_for_count--
} }
fn (mut c Checker) global_decl(node ast.GlobalDecl) { fn (mut c Checker) global_decl(mut node ast.GlobalDecl) {
for field in node.fields { for mut field in node.fields {
c.check_valid_snake_case(field.name, 'global name', field.pos) c.check_valid_snake_case(field.name, 'global name', field.pos)
if field.name in c.global_names { if field.name in c.global_names {
c.error('duplicate global `$field.name`', field.pos) c.error('duplicate global `$field.name`', field.pos)
@ -4803,6 +4803,14 @@ fn (mut c Checker) global_decl(node ast.GlobalDecl) {
if sym.kind == .placeholder { if sym.kind == .placeholder {
c.error('unknown type `$sym.name`', field.typ_pos) c.error('unknown type `$sym.name`', field.typ_pos)
} }
if field.expr !is ast.EmptyExpr {
expr_typ := c.expr(field.expr)
if !c.check_types(expr_typ, field.typ) {
got_sym := c.table.get_type_symbol(expr_typ)
c.error('cannot initialize global variable `$field.name` of type `$sym.name` with expression of type `$got_sym.name`',
field.expr.position())
}
}
c.global_names << field.name c.global_names << field.name
} }
} }

View File

@ -5113,9 +5113,18 @@ 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 { '' }
for field in node.fields { for field in node.fields {
if g.pref.skip_unused {
if field.name !in g.table.used_globals {
$if trace_skip_unused_globals ? {
eprintln('>> skipping unused global name: $field.name')
}
continue
}
}
styp := g.typ(field.typ) styp := g.typ(field.typ)
if field.has_expr { if field.has_expr {
g.definitions.writeln('$mod$styp $field.name = $field.expr; // global') g.definitions.writeln('$mod$styp $field.name;')
g.global_initializations.writeln('\t$field.name = ${g.expr_string(field.expr)}; // global')
} else { } else {
default_initializer := g.type_default(field.typ) default_initializer := g.type_default(field.typ)
if default_initializer == '{0}' { if default_initializer == '{0}' {

View File

@ -8,7 +8,7 @@ import v.pref
// mark_used walks the AST, starting at main() and marks all used fns transitively // mark_used walks the AST, starting at main() and marks all used fns transitively
pub fn mark_used(mut table ast.Table, pref &pref.Preferences, ast_files []&ast.File) { pub fn mark_used(mut table ast.Table, pref &pref.Preferences, ast_files []&ast.File) {
mut all_fns, all_consts := all_fn_and_const(ast_files) mut all_fns, all_consts, all_globals := all_fn_const_and_global(ast_files)
util.timing_start(@METHOD) util.timing_start(@METHOD)
defer { defer {
util.timing_measure(@METHOD) util.timing_measure(@METHOD)
@ -316,6 +316,7 @@ pub fn mark_used(mut table ast.Table, pref &pref.Preferences, ast_files []&ast.F
files: ast_files files: ast_files
all_fns: all_fns all_fns: all_fns
all_consts: all_consts all_consts: all_consts
all_globals: all_globals
pref: pref pref: pref
} }
// println( all_fns.keys() ) // println( all_fns.keys() )
@ -368,21 +369,24 @@ pub fn mark_used(mut table ast.Table, pref &pref.Preferences, ast_files []&ast.F
table.used_fns = walker.used_fns.move() table.used_fns = walker.used_fns.move()
table.used_consts = walker.used_consts.move() table.used_consts = walker.used_consts.move()
table.used_globals = walker.used_globals.move()
$if trace_skip_unused ? { $if trace_skip_unused ? {
eprintln('>> t.used_fns: $table.used_fns.keys()') eprintln('>> t.used_fns: $table.used_fns.keys()')
eprintln('>> t.used_consts: $table.used_consts.keys()') eprintln('>> t.used_consts: $table.used_consts.keys()')
eprintln('>> t.used_globals: $table.used_globals.keys()')
eprintln('>> walker.table.used_maps: $walker.table.used_maps') eprintln('>> walker.table.used_maps: $walker.table.used_maps')
} }
} }
fn all_fn_and_const(ast_files []&ast.File) (map[string]ast.FnDecl, map[string]ast.ConstField) { fn all_fn_const_and_global(ast_files []&ast.File) (map[string]ast.FnDecl, map[string]ast.ConstField, map[string]ast.GlobalField) {
util.timing_start(@METHOD) util.timing_start(@METHOD)
defer { defer {
util.timing_measure(@METHOD) util.timing_measure(@METHOD)
} }
mut all_fns := map[string]ast.FnDecl{} mut all_fns := map[string]ast.FnDecl{}
mut all_consts := map[string]ast.ConstField{} mut all_consts := map[string]ast.ConstField{}
mut all_globals := map[string]ast.GlobalField{}
for i in 0 .. ast_files.len { for i in 0 .. ast_files.len {
file := ast_files[i] file := ast_files[i]
for node in file.stmts { for node in file.stmts {
@ -397,9 +401,15 @@ fn all_fn_and_const(ast_files []&ast.File) (map[string]ast.FnDecl, map[string]as
all_consts[ckey] = cfield all_consts[ckey] = cfield
} }
} }
ast.GlobalDecl {
for gfield in node.fields {
gkey := gfield.name
all_globals[gkey] = gfield
}
}
else {} else {}
} }
} }
} }
return all_fns, all_consts return all_fns, all_consts, all_globals
} }

View File

@ -12,12 +12,14 @@ pub mut:
table &ast.Table table &ast.Table
used_fns map[string]bool // used_fns['println'] == true used_fns map[string]bool // used_fns['println'] == true
used_consts map[string]bool // used_consts['os.args'] == true used_consts map[string]bool // used_consts['os.args'] == true
used_globals map[string]bool
n_asserts int n_asserts int
pref &pref.Preferences pref &pref.Preferences
mut: mut:
files []&ast.File files []&ast.File
all_fns map[string]ast.FnDecl all_fns map[string]ast.FnDecl
all_consts map[string]ast.ConstField all_consts map[string]ast.ConstField
all_globals map[string]ast.GlobalField
} }
pub fn (mut w Walker) mark_fn_as_used(fkey string) { pub fn (mut w Walker) mark_fn_as_used(fkey string) {
@ -36,6 +38,15 @@ pub fn (mut w Walker) mark_const_as_used(ckey string) {
w.expr(cfield.expr) w.expr(cfield.expr)
} }
pub fn (mut w Walker) mark_global_as_used(ckey string) {
$if trace_skip_unused_marked ? {
eprintln(' global > |$ckey|')
}
w.used_globals[ckey] = true
gfield := w.all_globals[ckey] or { return }
w.expr(gfield.expr)
}
pub fn (mut w Walker) mark_root_fns(all_fn_root_names []string) { pub fn (mut w Walker) mark_root_fns(all_fn_root_names []string) {
for fn_name in all_fn_root_names { for fn_name in all_fn_root_names {
if fn_name !in w.used_fns { if fn_name !in w.used_fns {
@ -268,8 +279,11 @@ fn (mut w Walker) expr(node ast.Expr) {
.function { .function {
w.fn_by_name(node.name) w.fn_by_name(node.name)
} }
.global {
w.mark_global_as_used(node.name)
}
else { else {
// `.unresolved`, `.blank_ident`, `.variable`, `.global`, `.function` // `.unresolved`, `.blank_ident`, `.variable`, `.function`
// println('>>> else, ast.Ident kind: $node.kind') // println('>>> else, ast.Ident kind: $node.kind')
} }
} }