cgen: use the real C line number instead of #line 1000000 ... in the C footer with -g (#21388)

This commit is contained in:
Delyan Angelov 2024-04-30 17:03:53 +03:00 committed by GitHub
parent 08b6cc7af5
commit 00dd0bf938
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 52 additions and 8 deletions

View File

@ -56,7 +56,10 @@ pub fn build_c(mut b builder.Builder, v_files []string, out_file string) {
b.out_name_c = out_file b.out_name_c = out_file
b.pref.out_name_c = os.real_path(out_file) b.pref.out_name_c = os.real_path(out_file)
b.info('build_c(${out_file})') b.info('build_c(${out_file})')
output2 := gen_c(mut b, v_files) mut output2 := gen_c(mut b, v_files)
if b.pref.is_vlines {
output2 = c.fix_reset_dbg_line(output2, out_file)
}
os.write_file(out_file, output2) or { panic(err) } os.write_file(out_file, output2) or { panic(err) }
if b.pref.is_stats { if b.pref.is_stats {
b.stats_lines = output2.count('\n') + 1 b.stats_lines = output2.count('\n') + 1

View File

@ -523,7 +523,7 @@ pub fn gen(files []&ast.File, mut table ast.Table, pref_ &pref.Preferences) (str
g.finish() g.finish()
mut b := strings.new_builder(640000) mut b := strings.new_builder(g.out.len + 200_000)
b.write_string(g.hashes()) b.write_string(g.hashes())
if g.use_segfault_handler || g.pref.is_prof { if g.use_segfault_handler || g.pref.is_prof {
b.writeln('\n#define V_USE_SIGNAL_H') b.writeln('\n#define V_USE_SIGNAL_H')

View File

@ -2,6 +2,9 @@ module c
import v.util import v.util
import v.ast import v.ast
import strings
pub const reset_dbg_line = '#line 999999999'
pub fn (mut g Gen) gen_c_main() { pub fn (mut g Gen) gen_c_main() {
if !g.has_main { if !g.has_main {
@ -38,18 +41,56 @@ fn (mut g Gen) gen_vlines_reset() {
// At this point, the v files are transpiled. // At this point, the v files are transpiled.
// The rest is auto generated code, which will not have // The rest is auto generated code, which will not have
// different .v source file/line numbers. // different .v source file/line numbers.
//
// TODO: calculate the proper line here, based on
// the actual C lines in all the buffers
lines_so_far := 1000000
g.vlines_path = util.vlines_escape_path(g.pref.out_name_c, g.pref.ccompiler) g.vlines_path = util.vlines_escape_path(g.pref.out_name_c, g.pref.ccompiler)
g.writeln('') g.writeln('')
g.writeln('\n// Reset the file/line numbers') g.writeln('// Reset the C file/line numbers')
g.writeln('\n#line ${lines_so_far} "${g.vlines_path}"') g.writeln('${c.reset_dbg_line} "${g.vlines_path}"')
g.writeln('') g.writeln('')
} }
} }
pub fn fix_reset_dbg_line(src string, out_file string) string {
util.timing_start(@FN)
defer {
util.timing_measure(@FN)
}
// Note: using src.index() + a line counting loop + src.replace() here is slower,
// since it has to iterate over pretty much the entire src string several times.
// The loop below, does it just once, combining counting the lines, and finding the reset line:
mut dbg_reset_line_idx := 0
mut lines := 1
for idx, ob in src {
if ob == `\n` {
lines++
if unsafe { vmemcmp(src.str + idx + 1, c.reset_dbg_line.str, c.reset_dbg_line.len) } == 0 {
dbg_reset_line_idx = idx + 1
break
}
}
}
// find the position of the "..\..\..\src.tmp.c":
mut first_quote_idx := 0
for idx := dbg_reset_line_idx; idx < src.len; idx++ {
if unsafe { src.str[idx] } == `"` {
first_quote_idx = idx
break
}
}
// replace the reset line with the fixed line counter, keeping everything
// before and after it unchanged:
mut sb := strings.new_builder(src.len)
unsafe {
sb.write_ptr(src.str, dbg_reset_line_idx)
sb.write_string('#line ')
sb.write_decimal(lines)
sb.write_ptr(src.str + first_quote_idx - 1, src.len - first_quote_idx)
}
$if trace_reset_dbg_line ? {
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}')
}
return sb.str()
}
fn (mut g Gen) gen_c_main_function_only_header() { fn (mut g Gen) gen_c_main_function_only_header() {
if g.pref.cmain != '' { if g.pref.cmain != '' {
g.writeln('int ${g.pref.cmain}(int ___argc, char** ___argv){') g.writeln('int ${g.pref.cmain}(int ___argc, char** ___argv){')