Skip to content

Commit 00dd0bf

Browse files
authored
cgen: use the real C line number instead of #line 1000000 ... in the C footer with -g (#21388)
1 parent 08b6cc7 commit 00dd0bf

File tree

3 files changed

+52
-8
lines changed

3 files changed

+52
-8
lines changed

vlib/v/builder/cbuilder/cbuilder.v

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,10 @@ pub fn build_c(mut b builder.Builder, v_files []string, out_file string) {
5656
b.out_name_c = out_file
5757
b.pref.out_name_c = os.real_path(out_file)
5858
b.info('build_c(${out_file})')
59-
output2 := gen_c(mut b, v_files)
59+
mut output2 := gen_c(mut b, v_files)
60+
if b.pref.is_vlines {
61+
output2 = c.fix_reset_dbg_line(output2, out_file)
62+
}
6063
os.write_file(out_file, output2) or { panic(err) }
6164
if b.pref.is_stats {
6265
b.stats_lines = output2.count('\n') + 1

vlib/v/gen/c/cgen.v

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -523,7 +523,7 @@ pub fn gen(files []&ast.File, mut table ast.Table, pref_ &pref.Preferences) (str
523523

524524
g.finish()
525525

526-
mut b := strings.new_builder(640000)
526+
mut b := strings.new_builder(g.out.len + 200_000)
527527
b.write_string(g.hashes())
528528
if g.use_segfault_handler || g.pref.is_prof {
529529
b.writeln('\n#define V_USE_SIGNAL_H')

vlib/v/gen/c/cmain.v

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ module c
22

33
import v.util
44
import v.ast
5+
import strings
6+
7+
pub const reset_dbg_line = '#line 999999999'
58

69
pub fn (mut g Gen) gen_c_main() {
710
if !g.has_main {
@@ -38,18 +41,56 @@ fn (mut g Gen) gen_vlines_reset() {
3841
// At this point, the v files are transpiled.
3942
// The rest is auto generated code, which will not have
4043
// different .v source file/line numbers.
41-
//
42-
// TODO: calculate the proper line here, based on
43-
// the actual C lines in all the buffers
44-
lines_so_far := 1000000
4544
g.vlines_path = util.vlines_escape_path(g.pref.out_name_c, g.pref.ccompiler)
4645
g.writeln('')
47-
g.writeln('\n// Reset the file/line numbers')
48-
g.writeln('\n#line ${lines_so_far} "${g.vlines_path}"')
46+
g.writeln('// Reset the C file/line numbers')
47+
g.writeln('${c.reset_dbg_line} "${g.vlines_path}"')
4948
g.writeln('')
5049
}
5150
}
5251

52+
pub fn fix_reset_dbg_line(src string, out_file string) string {
53+
util.timing_start(@FN)
54+
defer {
55+
util.timing_measure(@FN)
56+
}
57+
// Note: using src.index() + a line counting loop + src.replace() here is slower,
58+
// since it has to iterate over pretty much the entire src string several times.
59+
// The loop below, does it just once, combining counting the lines, and finding the reset line:
60+
mut dbg_reset_line_idx := 0
61+
mut lines := 1
62+
for idx, ob in src {
63+
if ob == `\n` {
64+
lines++
65+
if unsafe { vmemcmp(src.str + idx + 1, c.reset_dbg_line.str, c.reset_dbg_line.len) } == 0 {
66+
dbg_reset_line_idx = idx + 1
67+
break
68+
}
69+
}
70+
}
71+
// find the position of the "..\..\..\src.tmp.c":
72+
mut first_quote_idx := 0
73+
for idx := dbg_reset_line_idx; idx < src.len; idx++ {
74+
if unsafe { src.str[idx] } == `"` {
75+
first_quote_idx = idx
76+
break
77+
}
78+
}
79+
// replace the reset line with the fixed line counter, keeping everything
80+
// before and after it unchanged:
81+
mut sb := strings.new_builder(src.len)
82+
unsafe {
83+
sb.write_ptr(src.str, dbg_reset_line_idx)
84+
sb.write_string('#line ')
85+
sb.write_decimal(lines)
86+
sb.write_ptr(src.str + first_quote_idx - 1, src.len - first_quote_idx)
87+
}
88+
$if trace_reset_dbg_line ? {
89+
eprintln('> reset_dbg_line: ${out_file}:${lines} | first_quote_idx: ${first_quote_idx} | src.len: ${src.len} | sb.len: ${sb.len} | sb.cap: ${sb.cap}')
90+
}
91+
return sb.str()
92+
}
93+
5394
fn (mut g Gen) gen_c_main_function_only_header() {
5495
if g.pref.cmain != '' {
5596
g.writeln('int ${g.pref.cmain}(int ___argc, char** ___argv){')

0 commit comments

Comments
 (0)