Skip to content

Commit 2de9fc0

Browse files
committed
v3: address active-header review feedback
1 parent 44d89ba commit 2de9fc0

4 files changed

Lines changed: 33 additions & 30 deletions

File tree

ci/qemu_linux_tests.sh

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -202,15 +202,15 @@ if ((provision)); then
202202
fi
203203

204204
host_head=$(git -C "$repo_root" rev-parse HEAD)
205-
guest_head=$(ssh "${ssh_options[@]}" "$guest" "git -C '${guest_repo}' rev-parse HEAD")
205+
printf -v guest_repo_q '%q' "$guest_repo"
206+
guest_head=$(ssh "${ssh_options[@]}" "$guest" "git -C ${guest_repo_q} rev-parse HEAD")
206207
if [[ "$host_head" != "$guest_head" ]]; then
207208
echo "Host and guest baselines differ (${host_head} != ${guest_head})." >&2
208209
echo "Update ${guest_repo} in the guest before syncing local changes." >&2
209210
exit 1
210211
fi
211212

212213
if ((sync_checkout)); then
213-
printf -v guest_repo_q '%q' "$guest_repo"
214214
# Remove every untracked path copied by the previous sync before restoring the
215215
# current set. This keeps a locally deleted untracked source from lingering in
216216
# guest module discovery without cleaning unrelated guest build artifacts.
@@ -267,7 +267,6 @@ if (($# == 0)); then
267267
set -- test-all
268268
fi
269269

270-
printf -v guest_repo_q '%q' "$guest_repo"
271270
printf -v jobs_q '%q' "$jobs"
272271
printf -v vflags_q '%q' "$vflags"
273272
printf -v no_fallback_q '%q' "$no_fallback"

doc/docs.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,9 @@ target OS different from the host, the established compiler in `vlib/v` is
8282
used. V scripts (`.vsh`, including `v run script.vsh`), the `crun` and
8383
`build-module` commands, and debug builds selected with `-g`/`-debug` also
8484
remain on the established compiler. Same-OS cross-architecture builds can still
85-
use V3 when the target is supported.
85+
use V3 when the target is supported. Copies or symlinks whose resolved compiler
86+
executable is not named `v` or `vnew` also remain on the established compiler by
87+
default; pass `-new-compiler` to select V3 explicitly in those installations.
8688

8789
You normally do not need to do anything: when V3 cannot yet build an eligible
8890
program, `v` automatically falls back to the established compiler, so your build

vlib/v3/gen/c/cleanc.v

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4530,12 +4530,12 @@ fn (mut g FlatGen) collect_preserved_header_file(path string, include_dirs []str
45304530
}
45314531
g.preserved_header_files_seen[real_path] = true
45324532
text := os.read_file(real_path) or { return }
4533-
possible_text := c_header_possible_active_text(text, g.c_flags, g.c99_mode, g.target)
4534-
g.collect_inlined_c_structs(possible_text)
4535-
g.collect_inlined_c_fns(possible_text)
4536-
g.collect_inlined_c_declared_fns(possible_text)
4533+
active_text := c_header_definitely_active_text(text, g.c_flags, g.c99_mode, g.target)
4534+
g.collect_inlined_c_structs(active_text)
4535+
g.collect_inlined_c_fns(active_text)
4536+
g.collect_inlined_c_declared_fns(active_text)
45374537
mut in_block_comment := false
4538-
for line in possible_text.split_into_lines() {
4538+
for line in active_text.split_into_lines() {
45394539
clean, next_in_block_comment := c_preprocessor_directive_scan_line(line, in_block_comment)
45404540
in_block_comment = next_in_block_comment
45414541
if c_directive_name(clean) !in ['include', 'import'] {
@@ -4559,17 +4559,17 @@ fn (mut g FlatGen) collect_preserved_header_file(path string, include_dirs []str
45594559
}
45604560
}
45614561

4562-
// c_header_possible_active_text removes declarations from preprocessor branches
4563-
// known to be inactive for the current target and C flags. Unknown branches stay
4564-
// in the scan so a declaration that the real compiler may see remains authoritative.
4565-
fn c_header_possible_active_text(text string, flags []string, c99_mode bool, target pref.Target) string {
4562+
// c_header_definitely_active_text retains declarations only from preprocessor
4563+
// branches known to be active for the current target and C flags. A declaration
4564+
// in an unresolved branch cannot safely suppress a generated C prototype.
4565+
fn c_header_definitely_active_text(text string, flags []string, c99_mode bool, target pref.Target) string {
45664566
mut defined := map[string]bool{}
45674567
mut undefined := map[string]bool{}
45684568
mut uncertain := map[string]bool{}
4569-
// A preserved header inherits macros from its including source and parent
4570-
// headers. That context is not carried through this lightweight recursive
4571-
// scan, so an otherwise unknown macro must keep both branches possible.
4572-
mut external_macros_possible := true
4569+
// Preinclude headers begin before generated source declarations. An earlier
4570+
// nested include can still introduce unknown macros, which makes later
4571+
// conditions unresolved and therefore unsuitable for prototype suppression.
4572+
mut external_macros_possible := false
45734573
mut i := 0
45744574
for i < flags.len {
45754575
clean := trimmed_space(flags[i])
@@ -4685,19 +4685,17 @@ fn c_header_possible_active_text(text string, flags []string, c99_mode bool, tar
46854685
output.writeln('')
46864686
continue
46874687
}
4688-
mut possibly_active := true
46894688
mut definitely_active := true
46904689
for depth in 0 .. condition_known.len {
46914690
if condition_known[depth] && !condition_active[depth] {
4692-
possibly_active = false
46934691
definitely_active = false
46944692
break
46954693
}
46964694
if !condition_known[depth] {
46974695
definitely_active = false
46984696
}
46994697
}
4700-
if !possibly_active {
4698+
if !definitely_active {
47014699
output.writeln('')
47024700
continue
47034701
}
@@ -4717,10 +4715,6 @@ fn c_header_possible_active_text(text string, flags []string, c99_mode bool, tar
47174715
defined.delete(macro_name)
47184716
undefined[macro_name] = true
47194717
}
4720-
} else {
4721-
defined.delete(macro_name)
4722-
undefined.delete(macro_name)
4723-
uncertain[macro_name] = true
47244718
}
47254719
}
47264720
}
@@ -4732,8 +4726,8 @@ fn c_header_possible_active_text(text string, flags []string, c99_mode bool, tar
47324726
fn c_preprocessor_ifdef_macro_state(name string, defined map[string]bool, undefined map[string]bool, uncertain map[string]bool, external_macros_possible bool, strict_iso_mode bool, target pref.Target) (bool, bool) {
47334727
if external_macros_possible && name !in defined && name !in undefined && name !in uncertain
47344728
&& name !in ['__linux__', '__linux', 'linux', 'unix', '__APPLE__', '__MACH__', '_WIN32', '_WIN64', '__FreeBSD__', '__OpenBSD__', '__NetBSD__'] {
4735-
// An earlier include can define an otherwise unknown macro. Keep both
4736-
// branches in that case so the declaration scan never drops active code.
4729+
// An earlier include can define an otherwise unknown macro, so its state
4730+
// cannot be inferred by this lightweight scan.
47374731
return false, true
47384732
}
47394733
return c_preprocessor_macro_state(name, defined, undefined, uncertain, strict_iso_mode, target)

vlib/v3/gen/c/source_directive_test.v

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ fn test_preserved_header_trees_scan_shared_files_once() {
5757
assert g.preserved_header_files_seen.len == 3
5858
}
5959

60-
fn test_preserved_header_ignores_known_inactive_declarations() {
60+
fn test_preserved_header_collects_only_definitely_active_declarations() {
6161
root := os.join_path(os.vtmp_dir(), 'v3_preserved_inactive_${os.getpid()}')
6262
os.rmdir_all(root) or {}
6363
os.mkdir_all(root) or { panic(err) }
@@ -71,18 +71,26 @@ fn test_preserved_header_ignores_known_inactive_declarations() {
7171
os.write_file(macro_header,
7272
'#if defined(PARENT_HEADER_FEATURE)\nint parent_enabled_fn(void);\n#endif\n#define PRESERVED_HEADER_FEATURE 1\n')!
7373
os.write_file(header,
74-
'#if 0\nint inactive_fn(void);\n#include "inactive.h"\n#else\nint active_fn(void);\n#endif\n#define PARENT_HEADER_FEATURE 1\n#include "macro.h"\n#if defined(PRESERVED_HEADER_FEATURE)\nint include_enabled_fn(void);\n#endif\n')!
74+
'#ifdef OPTIONAL_API\nint optional_fn(void);\n#endif\n#if 0\nint inactive_fn(void);\n#include "inactive.h"\n#else\nint active_fn(void);\n#endif\n#define PARENT_HEADER_FEATURE 1\n#include "macro.h"\n#if defined(PRESERVED_HEADER_FEATURE)\nint include_enabled_fn(void);\n#endif\n')!
7575

7676
mut g := FlatGen.new()
7777
g.collect_preserved_header_file(header, [root])
7878

7979
assert 'inactive_fn' !in g.inlined_c_declared_fns
8080
assert 'nested_inactive_fn' !in g.inlined_c_declared_fns
8181
assert 'active_fn' in g.inlined_c_declared_fns
82-
assert 'include_enabled_fn' in g.inlined_c_declared_fns
83-
assert 'parent_enabled_fn' in g.inlined_c_declared_fns
82+
assert 'optional_fn' !in g.inlined_c_declared_fns
83+
// Macro changes in recursively scanned headers are not carried back into the
84+
// parent scan, so those declarations cannot safely suppress prototypes either.
85+
assert 'include_enabled_fn' !in g.inlined_c_declared_fns
86+
assert 'parent_enabled_fn' !in g.inlined_c_declared_fns
8487
assert os.real_path(inactive_header) !in g.preserved_header_files_seen
8588
assert os.real_path(macro_header) in g.preserved_header_files_seen
89+
90+
mut enabled_g := FlatGen.new()
91+
enabled_g.c_flags << '-DOPTIONAL_API'
92+
enabled_g.collect_preserved_header_file(header, [root])
93+
assert 'optional_fn' in enabled_g.inlined_c_declared_fns
8694
}
8795

8896
fn collect_external_input_tree_status(root string, entry string, ambient_ambiguous bool) (bool, []string) {

0 commit comments

Comments
 (0)