Skip to content

Commit 8fb9bfd

Browse files
committed
v3: track final preinclude macro state
1 parent 818f63d commit 8fb9bfd

3 files changed

Lines changed: 83 additions & 22 deletions

File tree

vlib/v3/gen/c/cleanc.v

Lines changed: 48 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,7 @@ mut:
336336
inlined_c_typedef_names map[string]bool
337337
inlined_c_fns map[string]bool
338338
inlined_c_declared_fns map[string]bool
339+
inlined_c_active_macros map[string]bool
339340
possibly_active_c_macros map[string]bool
340341
inlined_c_static_fns map[string]bool
341342
cache_omitted_c_fns map[string]bool
@@ -1029,6 +1030,7 @@ pub fn FlatGen.new() FlatGen {
10291030
inlined_c_structs: map[string]bool{}
10301031
inlined_c_fns: map[string]bool{}
10311032
inlined_c_declared_fns: map[string]bool{}
1033+
inlined_c_active_macros: map[string]bool{}
10321034
possibly_active_c_macros: map[string]bool{}
10331035
inlined_c_static_fns: map[string]bool{}
10341036
cache_omitted_c_fns: map[string]bool{}
@@ -2615,6 +2617,7 @@ pub fn (mut g FlatGen) gen_with_used_options(a &flat.FlatAst, used_fns map[strin
26152617
g.inlined_c_structs.clear()
26162618
g.inlined_c_fns.clear()
26172619
g.inlined_c_declared_fns.clear()
2620+
g.inlined_c_active_macros.clear()
26182621
g.possibly_active_c_macros.clear()
26192622
g.inlined_c_static_fns.clear()
26202623
g.cache_omitted_c_fns.clear()
@@ -3377,6 +3380,9 @@ fn (mut g FlatGen) cache_user_c_string_symbols() map[string]bool {
33773380
for name in g.inlined_c_declared_fns.keys() {
33783381
collect_cache_numbered_string_symbols(name, mut symbols)
33793382
}
3383+
for name in g.inlined_c_active_macros.keys() {
3384+
collect_cache_numbered_string_symbols(name, mut symbols)
3385+
}
33803386
referenced_symbols := g.c_extern_referenced_symbols()
33813387
for name in referenced_symbols.keys() {
33823388
collect_cache_numbered_string_symbols(name, mut symbols)
@@ -4675,10 +4681,23 @@ fn (mut g FlatGen) collect_preserved_header_file_with_state_and_scope(path strin
46754681
if collect_declarations {
46764682
g.collect_inlined_c_structs(final_scan.text)
46774683
g.collect_inlined_c_fns(final_scan.text)
4678-
g.collect_inlined_c_declared_fns(final_scan.text)
4684+
g.collect_inlined_c_declarations(final_scan.text)
4685+
for macro_name in final_scan.macro_names {
4686+
if final_scan.final_state.defined[macro_name] {
4687+
g.inlined_c_active_macros[macro_name] = true
4688+
g.possibly_active_c_macros.delete(macro_name)
4689+
} else if final_scan.final_state.undefined[macro_name] {
4690+
g.inlined_c_active_macros.delete(macro_name)
4691+
g.possibly_active_c_macros.delete(macro_name)
4692+
} else {
4693+
g.inlined_c_active_macros.delete(macro_name)
4694+
g.possibly_active_c_macros[macro_name] = true
4695+
}
4696+
}
46794697
}
46804698
for macro_name in final_scan.possibly_active_macro_names {
4681-
if macro_name !in g.inlined_c_declared_fns {
4699+
if macro_name !in final_scan.final_state.undefined
4700+
&& macro_name !in g.inlined_c_active_macros && macro_name !in g.inlined_c_declared_fns {
46824701
g.possibly_active_c_macros[macro_name] = true
46834702
}
46844703
}
@@ -4701,6 +4720,7 @@ struct CHeaderActiveScan {
47014720
include_keys []string
47024721
include_args []string
47034722
include_definitely_active []bool
4723+
macro_names []string
47044724
possibly_active_macro_names []string
47054725
final_state CHeaderMacroState
47064726
}
@@ -4853,6 +4873,7 @@ fn c_header_definitely_active_scan_with_include_results(text string, state CHead
48534873
mut include_keys := []string{}
48544874
mut include_args := []string{}
48554875
mut include_definitely_active := []bool{}
4876+
mut macro_names := map[string]bool{}
48564877
mut possibly_active_macro_names := map[string]bool{}
48574878
mut output := strings.new_builder(text.len)
48584879
mut in_block_comment := false
@@ -4950,6 +4971,9 @@ fn c_header_definitely_active_scan_with_include_results(text string, state CHead
49504971
parts := c_directive_arg(clean).fields()
49514972
if parts.len > 0 {
49524973
macro_name := parts[0].all_before('(')
4974+
if possibly_active && macro_name.len > 0 {
4975+
macro_names[macro_name] = true
4976+
}
49534977
if name == 'define' && possibly_active && macro_name.len > 0 {
49544978
possibly_active_macro_names[macro_name] = true
49554979
}
@@ -5010,6 +5034,7 @@ fn c_header_definitely_active_scan_with_include_results(text string, state CHead
50105034
include_keys: include_keys
50115035
include_args: include_args
50125036
include_definitely_active: include_definitely_active
5037+
macro_names: macro_names.keys()
50135038
possibly_active_macro_names: possibly_active_macro_names.keys()
50145039
final_state: CHeaderMacroState{
50155040
defined: defined
@@ -8103,6 +8128,27 @@ fn c_strip_comments(text string) string {
81038128
}
81048129

81058130
fn (mut g FlatGen) collect_inlined_c_declared_fns(text string) {
8131+
g.collect_inlined_c_declarations(text)
8132+
// Inlined source text has not gone through the active-branch scanner. Keep
8133+
// every visible definition conservative, as before; only preserved headers
8134+
// can use their final preprocessor state to prove that a later #undef wins.
8135+
for line in c_strip_comments(text).split_into_lines() {
8136+
clean := line.trim_space()
8137+
if clean.len == 0 || clean[0] != `#` || c_directive_name(clean) != 'define' {
8138+
continue
8139+
}
8140+
arg := c_directive_arg(clean)
8141+
mut name_end := 0
8142+
for name_end < arg.len && c_ident_char(arg[name_end]) {
8143+
name_end++
8144+
}
8145+
if name_end > 0 {
8146+
g.inlined_c_active_macros[arg[..name_end]] = true
8147+
}
8148+
}
8149+
}
8150+
8151+
fn (mut g FlatGen) collect_inlined_c_declarations(text string) {
81068152
// Header declarations often span several lines (one parameter per line);
81078153
// accumulate a pending declaration until its terminating `;` so those are
81088154
// collected too, not just single-line prototypes.
@@ -8112,19 +8158,6 @@ fn (mut g FlatGen) collect_inlined_c_declared_fns(text string) {
81128158
for name in c_macro_declared_fn_names(clean) {
81138159
g.inlined_c_declared_fns[name] = true
81148160
}
8115-
if clean.len > 0 && clean[0] == `#` && c_directive_name(clean) == 'define' {
8116-
// Any macro (object- or function-like) named like a `fn C.x` makes
8117-
// an emitted extern prototype wrong after preprocessing; the
8118-
// header's definition is authoritative.
8119-
arg := c_directive_arg(clean)
8120-
mut name_end := 0
8121-
for name_end < arg.len && c_ident_char(arg[name_end]) {
8122-
name_end++
8123-
}
8124-
if name_end > 0 {
8125-
g.inlined_c_declared_fns[arg[..name_end]] = true
8126-
}
8127-
}
81288161
if pending.len > 0 {
81298162
if clean.len == 0 || clean[0] == `#` || clean.contains('{') || clean.contains('}')
81308163
|| pending.len > 4096 {

vlib/v3/gen/c/fn.v

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15140,12 +15140,13 @@ fn (g &FlatGen) should_emit_c_extern_decl(cfn string) bool {
1514015140
return false
1514115141
}
1514215142
if cfn in g.inlined_c_fns {
15143-
if g.cache_split && cfn in g.cache_omitted_c_fns && cfn !in g.inlined_c_declared_fns {
15143+
if g.cache_split && cfn in g.cache_omitted_c_fns && cfn !in g.inlined_c_declared_fns
15144+
&& cfn !in g.inlined_c_active_macros {
1514415145
return true
1514515146
}
1514615147
return false
1514715148
}
15148-
if cfn in g.inlined_c_declared_fns {
15149+
if cfn in g.inlined_c_declared_fns || cfn in g.inlined_c_active_macros {
1514915150
return false
1515015151
}
1515115152
return true
@@ -15248,7 +15249,7 @@ const c_manual_stdlib_declared_fns = {
1524815249

1524915250
fn (g &FlatGen) c_extern_decl_is_cached_object_fallback(cfn string) bool {
1525015251
return g.cache_split && cfn in g.inlined_c_fns && cfn in g.cache_omitted_c_fns
15251-
&& cfn !in g.inlined_c_declared_fns
15252+
&& cfn !in g.inlined_c_declared_fns && cfn !in g.inlined_c_active_macros
1525215253
}
1525315254

1525415255
fn (g &FlatGen) should_emit_c_extern_decl_from_file(cfn string, source_file string) bool {

vlib/v3/gen/c/source_directive_test.v

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ fn test_preinclude_carries_macro_state_to_later_preincludes() {
133133
typ: '"${api_header}"'
134134
}, source, false)
135135

136-
assert 'chained_api' in g.inlined_c_declared_fns
136+
assert 'chained_api' in g.inlined_c_active_macros
137137
assert g.preinclude_directives == ['#include "${config_header}"', '#include "${api_header}"']
138138
}
139139

@@ -187,7 +187,7 @@ fn test_preserved_header_carries_child_macros_into_parent_remainder() {
187187
mut g := FlatGen.new()
188188
g.collect_preserved_header_file(parent, [root])
189189

190-
assert 'enabled_api' in g.inlined_c_declared_fns
190+
assert 'enabled_api' in g.inlined_c_active_macros
191191
}
192192

193193
fn test_preserved_unguarded_header_is_rescanned_under_new_macro_state() {
@@ -205,7 +205,7 @@ fn test_preserved_unguarded_header_is_rescanned_under_new_macro_state() {
205205
mut g := FlatGen.new()
206206
g.collect_preserved_header_file(parent, [root])
207207

208-
assert 'enabled_api' in g.inlined_c_declared_fns
208+
assert 'enabled_api' in g.inlined_c_active_macros
209209
child_prefix := os.real_path(child) + '\n'
210210
assert g.preserved_header_scan_results.keys().filter(it.starts_with(child_prefix)).len >= 2
211211
}
@@ -226,7 +226,7 @@ fn test_preserved_header_passes_definite_parent_macro_state_to_children() {
226226
mut g := FlatGen.new()
227227
g.collect_preserved_header_file(parent, [root])
228228

229-
assert 'enabled_api' in g.inlined_c_declared_fns
229+
assert 'enabled_api' in g.inlined_c_active_macros
230230
assert 'omitted_api' !in g.inlined_c_declared_fns
231231
}
232232

@@ -279,6 +279,33 @@ fn test_preserved_header_guards_externs_for_possibly_active_function_macros() {
279279
assert 'inactive_api' !in g.possibly_active_c_macros
280280
}
281281

282+
fn test_preserved_headers_track_final_macro_state_for_externs() {
283+
root := os.join_path(os.vtmp_dir(), 'v3_preserved_final_macro_${os.getpid()}')
284+
os.rmdir_all(root) or {}
285+
os.mkdir_all(root)!
286+
defer {
287+
os.rmdir_all(root) or {}
288+
}
289+
first := os.join_path(root, 'first.h')
290+
second := os.join_path(root, 'second.h')
291+
os.write_file(first,
292+
'#define same_header_api(x) ((x) + 1)\n#undef same_header_api\n#define declared_api(x) ((x) + 2)\n#undef declared_api\nint declared_api(void);\n#define later_header_api(x) ((x) + 3)\n')!
293+
os.write_file(second, '#undef later_header_api\n')!
294+
295+
mut g := FlatGen.new()
296+
state := g.collect_preserved_header_file_with_state(first, [root], CHeaderMacroState{})
297+
assert 'same_header_api' !in g.inlined_c_active_macros
298+
assert 'later_header_api' in g.inlined_c_active_macros
299+
assert 'declared_api' in g.inlined_c_declared_fns
300+
assert g.should_emit_c_extern_decl('same_header_api')
301+
assert !g.should_emit_c_extern_decl('later_header_api')
302+
assert !g.should_emit_c_extern_decl('declared_api')
303+
g.collect_preserved_header_file_with_state(second, [root], state)
304+
assert 'later_header_api' !in g.inlined_c_active_macros
305+
assert g.should_emit_c_extern_decl('later_header_api')
306+
assert !g.should_emit_c_extern_decl('declared_api')
307+
}
308+
282309
fn test_preserved_header_scans_includes_in_possibly_active_branches_for_macros() {
283310
root := os.join_path(os.vtmp_dir(), 'v3_preserved_possible_include_${os.getpid()}')
284311
os.rmdir_all(root) or {}

0 commit comments

Comments
 (0)