cgen: properly handle initialization expression for globals (#10981)
							parent
							
								
									61ed1d810f
								
							
						
					
					
						commit
						45ad48d76a
					
				|  | @ -535,11 +535,11 @@ pub: | |||
| pub struct GlobalField { | ||||
| pub: | ||||
| 	name     string | ||||
| 	expr     Expr | ||||
| 	has_expr bool | ||||
| 	pos      token.Position | ||||
| 	typ_pos  token.Position | ||||
| pub mut: | ||||
| 	expr     Expr | ||||
| 	typ      Type | ||||
| 	comments []Comment | ||||
| } | ||||
|  |  | |||
|  | @ -26,6 +26,7 @@ pub mut: | |||
| 	is_fmt             bool | ||||
| 	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_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_maps          int    // how many times maps were used, filled in by checker, when pref.skip_unused = true;
 | ||||
| 	panic_handler      FnPanicHandler = default_table_panic_handler | ||||
|  | @ -52,6 +53,7 @@ pub fn (t &Table) free() { | |||
| 		t.cmod_prefix.free() | ||||
| 		t.used_fns.free() | ||||
| 		t.used_consts.free() | ||||
| 		t.used_globals.free() | ||||
| 		t.used_vweb_types.free() | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -4544,7 +4544,7 @@ fn (mut c Checker) stmt(node ast.Stmt) { | |||
| 			c.for_stmt(mut node) | ||||
| 		} | ||||
| 		ast.GlobalDecl { | ||||
| 			c.global_decl(node) | ||||
| 			c.global_decl(mut node) | ||||
| 		} | ||||
| 		ast.GotoLabel {} | ||||
| 		ast.GotoStmt { | ||||
|  | @ -4793,8 +4793,8 @@ fn (mut c Checker) for_stmt(mut node ast.ForStmt) { | |||
| 	c.in_for_count-- | ||||
| } | ||||
| 
 | ||||
| fn (mut c Checker) global_decl(node ast.GlobalDecl) { | ||||
| 	for field in node.fields { | ||||
| fn (mut c Checker) global_decl(mut node ast.GlobalDecl) { | ||||
| 	for mut field in node.fields { | ||||
| 		c.check_valid_snake_case(field.name, 'global name', field.pos) | ||||
| 		if field.name in c.global_names { | ||||
| 			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 { | ||||
| 			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 | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -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) { | ||||
| 	mod := if g.pref.build_mode == .build_module && g.is_builtin_mod { 'static ' } else { '' } | ||||
| 	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) | ||||
| 		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 { | ||||
| 			default_initializer := g.type_default(field.typ) | ||||
| 			if default_initializer == '{0}' { | ||||
|  |  | |||
|  | @ -8,7 +8,7 @@ import v.pref | |||
| 
 | ||||
| // 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) { | ||||
| 	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) | ||||
| 	defer { | ||||
| 		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 | ||||
| 		all_fns: all_fns | ||||
| 		all_consts: all_consts | ||||
| 		all_globals: all_globals | ||||
| 		pref: pref | ||||
| 	} | ||||
| 	// 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_consts = walker.used_consts.move() | ||||
| 	table.used_globals = walker.used_globals.move() | ||||
| 
 | ||||
| 	$if trace_skip_unused ? { | ||||
| 		eprintln('>> t.used_fns: $table.used_fns.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') | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 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) | ||||
| 	defer { | ||||
| 		util.timing_measure(@METHOD) | ||||
| 	} | ||||
| 	mut all_fns := map[string]ast.FnDecl{} | ||||
| 	mut all_consts := map[string]ast.ConstField{} | ||||
| 	mut all_globals := map[string]ast.GlobalField{} | ||||
| 	for i in 0 .. ast_files.len { | ||||
| 		file := ast_files[i] | ||||
| 		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 | ||||
| 					} | ||||
| 				} | ||||
| 				ast.GlobalDecl { | ||||
| 					for gfield in node.fields { | ||||
| 						gkey := gfield.name | ||||
| 						all_globals[gkey] = gfield | ||||
| 					} | ||||
| 				} | ||||
| 				else {} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return all_fns, all_consts | ||||
| 	return all_fns, all_consts, all_globals | ||||
| } | ||||
|  |  | |||
|  | @ -9,15 +9,17 @@ import v.pref | |||
| 
 | ||||
| pub struct Walker { | ||||
| pub mut: | ||||
| 	table       &ast.Table | ||||
| 	used_fns    map[string]bool // used_fns['println'] == true
 | ||||
| 	used_consts map[string]bool // used_consts['os.args'] == true
 | ||||
| 	n_asserts   int | ||||
| 	pref        &pref.Preferences | ||||
| 	table        &ast.Table | ||||
| 	used_fns     map[string]bool // used_fns['println'] == true
 | ||||
| 	used_consts  map[string]bool // used_consts['os.args'] == true
 | ||||
| 	used_globals map[string]bool | ||||
| 	n_asserts    int | ||||
| 	pref         &pref.Preferences | ||||
| mut: | ||||
| 	files      []&ast.File | ||||
| 	all_fns    map[string]ast.FnDecl | ||||
| 	all_consts map[string]ast.ConstField | ||||
| 	files       []&ast.File | ||||
| 	all_fns     map[string]ast.FnDecl | ||||
| 	all_consts  map[string]ast.ConstField | ||||
| 	all_globals map[string]ast.GlobalField | ||||
| } | ||||
| 
 | ||||
| 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) | ||||
| } | ||||
| 
 | ||||
| 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) { | ||||
| 	for fn_name in all_fn_root_names { | ||||
| 		if fn_name !in w.used_fns { | ||||
|  | @ -268,8 +279,11 @@ fn (mut w Walker) expr(node ast.Expr) { | |||
| 				.function { | ||||
| 					w.fn_by_name(node.name) | ||||
| 				} | ||||
| 				.global { | ||||
| 					w.mark_global_as_used(node.name) | ||||
| 				} | ||||
| 				else { | ||||
| 					// `.unresolved`, `.blank_ident`, `.variable`, `.global`, `.function`
 | ||||
| 					// `.unresolved`, `.blank_ident`, `.variable`, `.function`
 | ||||
| 					// println('>>> else, ast.Ident kind: $node.kind')
 | ||||
| 				} | ||||
| 			} | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue