Problem with public example in Phobos

Steven Schveighoffer schveiguy at
Wed Dec 18 17:57:15 UTC 2019

On 12/18/19 3:56 AM, berni44 wrote:
> I thought it's a fast fix, just adding some documentation and a 
> unittest. But when running the style checker I got into trouble. A 
> shortend version of the problem:
> I added the following public unittest to writeUpToNextSpec in std.format:
>      ///
>      @safe unittest
>      {
>          import std.array;
>          auto w = appender!(char[])();
>          auto f = FormatSpec("input: %10d output: %s");
>          assert(f.writeUpToNextSpec(w) == true);
>          assert( == "input: ");
>          assert(f.spec == 'd');
>          assert(f.width == 10);
>          // [...]
>      }
> While it works with the normal unittest test routines (make -f posix.mak 
> unittest) the stylechecker complains (make -f posix.mak style).

style checker has nothing to do with buildable code. It just enforces 
the style follows the guidelines.

Just look at the output and see what it's asking you to do.

> I meanwhile found out, that I have to add the template parameter dchar 
> to FormatSpec, although I don't understand why. (I know, that these 
> tests should work, when they are put into a separate file. But I do not 
> understand why the original version doesn't work there.)

OK, so writeUpToNextSpec is a method inside a templated struct 
(FormatSpec). *Inside* any templated struct (or template of any kind 
really), the name of the template is synonymous with the *instantiated* 


struct S(T)
    S *ptr;

static assert(is(typeof(S!int.ptr) == S!int *));

But when the code is copied *outside* the template, it needs the full 

This comes from the fact that unless you are declaring a template with 
`template`, you are using the eponymous template trick under the hood.

That is:

struct S(T)

is short for:

template S(T)
    struct S

where naturally the S inside the template is not the template but the 

In the case of a documented unittest, I think the CI is trying to make 
sure the test can run on its own.

Note, putting unittests inside templates duplicates the unit test for 
every instantiation. Using an instantiation other than the template 
itself is going to result in a lot of duplicated tests. Unfortunately, 
there is no mechanism to have a documented unittest that isn't part of 
the instantiation.

> But more problematic: When I add this templete parameter, I still get an 
> error from the style checker, this time it's a linker problem, and I'm 
> completely lost here. The error does not occure when checking 
> std.format, but when checking std.package:
> parsing std/package.d
> /usr/bin/ld: std_package.o: in function 
> `_D3std6format__T10FormatSpecTaZQp22__unittest_L1237_C11_1FNaNfZv':
> __main.d:(.text._D3std6format__T10FormatSpecTaZQp22__unittest_L1237_C11_1FNaNfZv[_D3std6format__T10FormatSpecTaZQp22__unittest_L1237_C11_1FNaNfZv]+0x17): 
> undefined reference to `_D3std6format__T10FormatSpecTwZQp6__initZ'
> /usr/bin/ld: 
> __main.d:(.text._D3std6format__T10FormatSpecTaZQp22__unittest_L1237_C11_1FNaNfZv[_D3std6format__T10FormatSpecTaZQp22__unittest_L1237_C11_1FNaNfZv]+0x38): 
> undefined reference to 
> `_D3std6format__T10FormatSpecTwZQp6__ctorMFNaNbNcNiNfxAwZSQCdQCc__TQByTwZQCe' 
> /usr/bin/ld: std_package.o: in function 
> `_D3std6format__T10FormatSpecTwZQp__T17writeUpToNextSpecTSQCd5array__T8AppenderTAaZQnZQBxMFNaNlNfKQBpZb': 
> __main.d:(.text._D3std6format__T10FormatSpecTwZQp__T17writeUpToNextSpecTSQCd5array__T8AppenderTAaZQnZQBxMFNaNlNfKQBpZb[_D3std6format__T10FormatSpecTwZQp__T17writeUpToNextSpecTSQCd5array__T8AppenderTAaZQnZQBxMFNaNlNfKQBpZb]+0x15a): 
> undefined reference to `_D3std6format__T10FormatSpecTwZQp6fillUpMFNaNlNfZv'

This might be a bug. I don't know how this is built, so I'm not sure. 
But it looks like the compiler isn't including some instantiation of 
FormatSpec when linking.


More information about the Digitalmars-d-learn mailing list