Skip to content

Commit 02f9ca3

Browse files
committed
fix code coverage bug in tail position and else
This was due to lowering keeping the same location info for the inserted `return` or `goto` statement, even though the last seen location might not have executed.
1 parent e460d35 commit 02f9ca3

File tree

4 files changed

+96
-19
lines changed

4 files changed

+96
-19
lines changed

base/compiler/ssair/inlining.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1818,7 +1818,9 @@ end
18181818

18191819
function ssa_substitute!(insert_node!::Inserter, subst_inst::Instruction, @nospecialize(val),
18201820
ssa_substitute::SSASubstitute)
1821-
subst_inst[:line] += ssa_substitute.linetable_offset
1821+
if subst_inst[:line] != 0
1822+
subst_inst[:line] += ssa_substitute.linetable_offset
1823+
end
18221824
return ssa_substitute_op!(insert_node!, subst_inst, val, ssa_substitute)
18231825
end
18241826

base/compiler/ssair/passes.jl

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1519,8 +1519,12 @@ function try_inline_finalizer!(ir::IRCode, argexprs::Vector{Any}, idx::Int,
15191519
ssa_rename[ssa.id]
15201520
end
15211521
stmt′ = ssa_substitute_op!(InsertBefore(ir, SSAValue(idx)), inst, stmt′, ssa_substitute)
1522+
newline = inst[:line]
1523+
if newline != 0
1524+
newline += ssa_substitute.linetable_offset
1525+
end
15221526
ssa_rename[idx′] = insert_node!(ir, idx,
1523-
NewInstruction(inst; stmt=stmt′, line=inst[:line]+ssa_substitute.linetable_offset),
1527+
NewInstruction(inst; stmt=stmt′, line=newline),
15241528
attach_after)
15251529
end
15261530

src/julia-syntax.scm

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4380,8 +4380,9 @@ f(x) = yt(x)
43804380
(begin (emit `(= ,tmp ,x)) tmp)
43814381
x)))
43824382
(define (actually-return x)
4383-
(let* ((x (if rett
4384-
(compile (convert-for-type-decl (emit- x) rett #t lam) '() #t #f)
4383+
(let* ((x (begin0 (emit- x) (emit '(line #f))))
4384+
(x (if rett
4385+
(compile (convert-for-type-decl x rett #t lam) '() #t #f)
43854386
x))
43864387
(x (emit- x)))
43874388
(let ((pexc (pop-exc-expr catch-token-stack '())))
@@ -4662,7 +4663,8 @@ f(x) = yt(x)
46624663
(let ((v1 (compile (caddr e) break-labels value tail)))
46634664
(if val (emit-assignment val v1))
46644665
(if (and (not tail) (or (length> e 3) val))
4665-
(emit end-jump))
4666+
(begin (emit `(line #f))
4667+
(emit end-jump)))
46664668
(let ((elselabel (make&mark-label)))
46674669
(for-each (lambda (test)
46684670
(set-car! (cddr test) elselabel))
@@ -5046,20 +5048,26 @@ f(x) = yt(x)
50465048
(let ((e (car stmts)))
50475049
(cond ((atom? e) (emit e))
50485050
((eq? (car e) 'line)
5049-
(if (and (= current-line 0) (length= e 2) (pair? linetable))
5050-
;; (line n) after push_loc just updates the line for the new file
5051-
(begin (set-lineno! (car linetable) (cadr e))
5052-
(set! current-line (cadr e)))
5053-
(begin
5054-
(set! current-line (cadr e))
5055-
(if (pair? (cddr e))
5056-
(set! current-file (caddr e)))
5057-
(set! linetable (cons (if (null? locstack)
5058-
(make-lineinfo name current-file current-line)
5059-
(make-lineinfo name current-file current-line (caar locstack)))
5060-
linetable))
5061-
(set! linetablelen (+ linetablelen 1))
5062-
(set! current-loc linetablelen))))
5051+
(cond ((and (length= e 2) (not (cadr e)))
5052+
;; (line #f) marks that we are entering a generated statement
5053+
;; that should not be counted as belonging to the previous marked location,
5054+
;; for example `return` after a not-executed `if` arm in tail position.
5055+
(set! current-loc 0))
5056+
((and (= current-line 0) (length= e 2) (pair? linetable))
5057+
;; (line n) after push_loc just updates the line for the new file
5058+
(begin (set-lineno! (car linetable) (cadr e))
5059+
(set! current-line (cadr e))))
5060+
(else
5061+
(begin
5062+
(set! current-line (cadr e))
5063+
(if (pair? (cddr e))
5064+
(set! current-file (caddr e)))
5065+
(set! linetable (cons (if (null? locstack)
5066+
(make-lineinfo name current-file current-line)
5067+
(make-lineinfo name current-file current-line (caar locstack)))
5068+
linetable))
5069+
(set! linetablelen (+ linetablelen 1))
5070+
(set! current-loc linetablelen)))))
50635071
((and (length> e 2) (eq? (car e) 'meta) (eq? (cadr e) 'push_loc))
50645072
(set! locstack (cons (list current-loc current-line current-file) locstack))
50655073
(set! current-file (caddr e))

test/cmdlineargs.jl

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,69 @@ let exename = `$(Base.julia_cmd()) --startup-file=no --color=no`
545545
got = read(covfile, String)
546546
@test isempty(got)
547547
rm(covfile)
548+
549+
function coverage_info_for(src::String)
550+
mktemp(dir) do srcfile, io
551+
write(io, src); close(io)
552+
outfile = tempname(dir, cleanup=false)*".info"
553+
run(`$exename --code-coverage=$outfile $srcfile`)
554+
result = read(outfile, String)
555+
rm(outfile, force=true)
556+
result
557+
end
558+
end
559+
@test contains(coverage_info_for("""
560+
function cov_bug(x, p)
561+
if p > 2
562+
print("") # runs
563+
end
564+
if Base.compilerbarrier(:const, false)
565+
println("Does not run")
566+
end
567+
end
568+
function do_test()
569+
cov_bug(5, 3)
570+
end
571+
do_test()
572+
"""), """
573+
DA:1,1
574+
DA:2,1
575+
DA:3,1
576+
DA:5,1
577+
DA:6,0
578+
DA:9,1
579+
DA:10,1
580+
LH:6
581+
LF:7
582+
""")
583+
@test contains(coverage_info_for("""
584+
function cov_bug()
585+
if Base.compilerbarrier(:const, true)
586+
if Base.compilerbarrier(:const, true)
587+
if Base.compilerbarrier(:const, false)
588+
println("Does not run")
589+
end
590+
else
591+
print("Does not run either")
592+
end
593+
else
594+
print("")
595+
end
596+
return nothing
597+
end
598+
cov_bug()
599+
"""), """
600+
DA:1,1
601+
DA:2,1
602+
DA:3,1
603+
DA:4,1
604+
DA:5,0
605+
DA:8,0
606+
DA:11,0
607+
DA:13,1
608+
LH:5
609+
LF:8
610+
""")
548611
end
549612

550613
# --track-allocation

0 commit comments

Comments
 (0)