@@ -2497,10 +2497,47 @@ fn register_native_source_typedefs(mut tc types.TypeChecker, state &V3ModuleCach
24972497 if c_name ! in tc.structs {
24982498 tc.structs[c_name] = []types.StructField{}
24992499 }
2500- tc.c_typedef_structs[c_name] = true
2500+ if ! c_typedef_is_function_pointer (source, name) {
2501+ tc.c_typedef_structs[c_name] = true
2502+ }
2503+ }
2504+ }
2505+ }
2506+ }
2507+
2508+ fn register_headerless_c_types (mut tc types.TypeChecker) {
2509+ // The C backend always supplies this platform-specific declaration in its
2510+ // headerless preamble, even when the program does not import `os`.
2511+ if 'C.stat' ! in tc.structs {
2512+ tc.structs['C.stat' ] = []types.StructField{}
2513+ }
2514+ }
2515+
2516+ fn c_typedef_is_function_pointer (source string , name string ) bool {
2517+ mut offset := 0
2518+ for offset < source.len {
2519+ relative := source[offset..].index (name) or { return false }
2520+ start := offset + relative
2521+ end := start + name.len
2522+ if (start == 0 || (! source[start - 1 ].is_alnum () && source[start - 1 ] != `_` ))
2523+ && (end == source.len || (! source[end].is_alnum () && source[end] != `_` )) {
2524+ mut i := start - 1
2525+ for i > = 0 && source[i].is_space () {
2526+ i--
2527+ }
2528+ if i > = 0 && source[i] == `*` {
2529+ i--
2530+ for i > = 0 && source[i].is_space () {
2531+ i--
2532+ }
2533+ if i > = 0 && source[i] == `(` {
2534+ return true
2535+ }
25012536 }
25022537 }
2538+ offset = end
25032539 }
2540+ return false
25042541}
25052542
25062543fn cache_c_compiler_predefined_macros (flags []string , ccompiler string , target pref.Target, native_inputs_language string ) (map [string ]string , bool ) {
@@ -4858,7 +4895,7 @@ fn incremental_changed_functions(snapshot V3IncrementalSnapshot, old map[string]
48584895 return keys, names
48594896}
48604897
4861- fn incremental_changed_functions_require_reachability_rebuild (a & flat.FlatAst, tc & types.TypeChecker, changed_names map [string ]bool , cached map [string ]bool , user_files []string ) bool {
4898+ fn incremental_changed_functions_require_reachability_rebuild (a & flat.FlatAst, tc & types.TypeChecker, mut changed_names map [string ]bool , mut used map [string ]bool , user_files []string ) bool {
48624899 if changed_names.len == 0 {
48634900 return false
48644901 }
@@ -4891,7 +4928,17 @@ fn incremental_changed_functions_require_reachability_rebuild(a &flat.FlatAst, t
48914928 if ! aliases.any (current[it ]) {
48924929 continue
48934930 }
4894- if ! aliases.any (cached[it ]) {
4931+ if ! aliases.any (used[it ]) {
4932+ // A newly reached stringifier can be added to the incremental body without
4933+ // invalidating unchanged functions or the cached support prefix.
4934+ if name.ends_with ('.str' ) {
4935+ changed_names[node.value] = true
4936+ changed_names[name] = true
4937+ for alias in aliases {
4938+ used[alias] = true
4939+ }
4940+ continue
4941+ }
48954942 return true
48964943 }
48974944 }
@@ -7967,6 +8014,7 @@ pub fn run(args []string) {
79678014 }
79688015 mut cvsw := time.new_stopwatch ()
79698016 pre_tc.collect (a)
8017+ register_headerless_c_types (mut pre_tc)
79708018 register_native_source_typedefs (mut pre_tc, & cache_state)
79718019 if translated_mode {
79728020 for file in user_files {
@@ -8204,7 +8252,7 @@ pub fn run(args []string) {
82048252 used_fns = clone_string_bool_map (cached_program_used_fns)
82058253 uses_generics = true
82068254 if incremental_cache_hit
8207- && incremental_changed_functions_require_reachability_rebuild (a, markused_tc, incremental_changed_names, cached_program_used_fns , user_files) {
8255+ && incremental_changed_functions_require_reachability_rebuild (a, markused_tc, mut incremental_changed_names, mut used_fns , user_files) {
82088256 os.setenv ('V3_CACHE_DISABLE_INCREMENTAL' , '1' , true )
82098257 restart_v3_after_cache_invalidation ()
82108258 }
@@ -8757,8 +8805,8 @@ pub fn run(args []string) {
87578805 base_specialized_fns := a.specialized_fn_nodes.len
87588806 monomorph_scope := prealloc_scope_begin_for_v3 ()
87598807 monomorph_used_fns , monomorph_errors , generated_monomorph_specs = transform.monomorphize_with_used_checked_config_scoped_cached (mut a,
8760- & pre_tc, monomorph_input_used, should_parallel_monomorphize (), monomorph_scope,
8761- cached_monomorph_specs)
8808+ & pre_tc, monomorph_input_used, ! current_no_parallel
8809+ && should_parallel_monomorphize (), monomorph_scope, cached_monomorph_specs)
87628810 parse_cache_enabled := pre_tc.type_cache_parse_enabled ()
87638811 prealloc_scope_leave_for_v3 (monomorph_scope)
87648812 // Specialization can rewrite payload text on pre-existing nodes as
@@ -8798,8 +8846,9 @@ pub fn run(args []string) {
87988846 prealloc_scope_free_for_v3 (monomorph_scope)
87998847 } else {
88008848 monomorph_used_fns , monomorph_errors , generated_monomorph_specs = transform.monomorphize_with_used_checked_config_scoped_cached (mut a,
8801- & pre_tc, monomorph_input_used, should_parallel_monomorphize ()
8802- && ! incremental_cache_hit, unsafe { nil }, cached_monomorph_specs)
8849+ & pre_tc, monomorph_input_used, ! current_no_parallel
8850+ && should_parallel_monomorphize () && ! incremental_cache_hit, unsafe { nil },
8851+ cached_monomorph_specs)
88038852 }
88048853 // Monomorphization publishes every synthesized or rewritten AST string
88058854 // after its final worker merge, including the serial/no-worker path.
@@ -11630,7 +11679,9 @@ fn vmod_subdirs(dir string) ![]string {
1163011679 if os.read_file (vmod_path)! .trim_space ().len == 0 {
1163111680 return []string {}
1163211681 }
11633- manifest := vmod.from_file (vmod_path)!
11682+ // An invalid v.mod does not make the source directory invalid. This matches
11683+ // the legacy builder, while still honoring `subdirs` in valid manifests.
11684+ manifest := vmod.from_file (vmod_path) or { return []string {} }
1163411685 return manifest.unknown['subdirs' ] or { []string {} }
1163511686}
1163611687
@@ -11747,8 +11798,7 @@ fn same_dir_module_source_files(test_file string, module_name string, prefs &pre
1174711798 if module_name.len > 0 {
1174811799 for file in all_files {
1174911800 declared_module := declared_module_in_file (file)
11750- if declared_module != module_name && ! (declared_module in ['' , 'main' ]
11751- && module_name in ['' , 'main' ]) {
11801+ if declared_module != module_name {
1175211802 continue
1175311803 }
1175411804 files << file
0 commit comments