July 10, 2020
https://issues.dlang.org/show_bug.cgi?id=21032

          Issue ID: 21032
           Summary: Code coverage (-cov) with templates with nested
                    functions of different types
           Product: D
           Version: D2
          Hardware: All
                OS: All
            Status: NEW
          Severity: enhancement
          Priority: P1
         Component: dmd
          Assignee: nobody@puremagic.com
          Reporter: john.michael.hall@gmail.com

-cov will not report missing coverage in the case of templates with nested functions whose top-level type is not used as part of any lower level function templates.

Compiling below with `dmd -unittest -cov covtest.d` and running to get the associated coverage file (below that) shows 100% even though the function foo with one parameter is not called.

The function foo with two parameters is correctly marked as being called. While the version of foo with one parameter is not marked, it also the 0000000 you would see in the case of bar or baz below if their one parameter versions were not included.

This is somewhat related to issue 9721 (https://issues.dlang.org/show_bug.cgi?id=9721), but that issue is about more general templates and this is only concerning templates with nested functions. In particular, it seems the issue appears when the type of the top-level template does not match one of the template parameters in the lower-levels.


covtest.d
```
module covtest;

enum Test {
    test1,
    test2
}

template foo(Test test) {
    T foo(T)(T x, T y) {
        return x + y;
    }

    T foo(T)(T x) {
        return x;
    }
}

unittest {
    assert(foo!(Test.test1)(1, 2) == 3);
}

template bar(T) {
    T bar(U)(T x, U y) {
        return x + cast(T) y;
    }

    T bar(T x) {
        return x;
    }
}

unittest {
    assert(bar!int(1, 2f) == 3);
    assert(bar!int(1) == 1);
}

int baz(int x, int y) {
    return x + y;
}

int baz(int x) {
    return x;
}

unittest {
    assert(baz(1, 2) == 3);
    assert(baz(1) == 1);
}

void main() {

}
```

covtest.lst
```
       |module covtest;
       |
       |enum Test {
       |    test1,
       |    test2
       |}
       |
       |template foo(Test test) {
       |    T foo(T)(T x, T y) {
      1|        return x + y;
       |    }
       |
       |    T foo(T)(T x) {
       |        return x;
       |    }
       |}
       |
       |unittest {
      1|    assert(foo!(Test.test1)(1, 2) == 3);
       |}
       |
       |template bar(T) {
       |    T bar(U)(T x, U y) {
      1|        return x + cast(T) y;
       |    }
       |
       |    T bar(T x) {
      1|        return x;
       |    }
       |}
       |
       |unittest {
      1|    assert(bar!int(1, 2f) == 3);
      1|    assert(bar!int(1) == 1);
       |}
       |
       |int baz(int x, int y) {
      1|    return x + y;
       |}
       |
       |int baz(int x) {
      1|    return x;
       |}
       |
       |unittest {
      1|    assert(baz(1, 2) == 3);
      1|    assert(baz(1) == 1);
       |}
       |
       |void main() {
       |
       |}
covtest.d is 100% covered

```

--