Thread overview
Name mangling is broken for integral template value arguments.
Feb 06, 2006
Don Clugston
Feb 07, 2006
Walter Bright
Feb 07, 2006
Walter Bright
Feb 08, 2006
Don Clugston
Feb 11, 2006
Thomas Kuehne
February 06, 2006
The ABI page of the docs says the name mangling scheme is:

TemplateArg:
    T Type
    V Value
    S LName

Value:
    n
    Number       <----- this is wrong
    N Number
    e 20HexDigits
    c 20HexDigits 20HexDigits
    Width Number _ HexDigits

So for example, given myTemplate!(37)
it would be
V37
but this is not what actually happens. Instead, the type comes after the V. It's "i" (integer) in this case, so we get
Vi37
I think this is good; it's more general, and it allows the possibility of template value arguments being different for (say) char and int.
I think the mangling rule should be:
TemplateArg:
    T Type
    V ValueArg
    S LName

ValueArg:
   Type Value

and Value is Number for positive integral types, N Number for negative ints, hex digits for real/ireals, 2 x hex digits for creals,
hex digits for strings. This is almost, but not quite, what happens now.

I ran into this problem trying to make a toString!() metafunction; it would be nice to be able to distinguish toString!('A') --> returns "A"
and toString!(65) --> returns "65".
(However, you _can_ already make a seperate toString!(real) and toString!(creal), because they use different mangling rules).

The problem is, the type used inside the mangled name seems to depend on how the template is SPECIALISED, but not on how it is DECLARED. So this example fails:

-------
    template frog(int F)
    {
        const int frog = 2;
    }

    template frog(int F:'A')
    {
        const int frog = 3;
    }
    static assert( frog!('A')==3);
---------
It fails because the second template is not actually a specialisation of the first one! But, the following code works:
------
    template frog(char F)
    {
        const int frog = 2;
    }

    template frog(char F:'A')
    {
        const int frog = 3;
    }
    static assert( frog!('A')==3);
------
Even more interesting is to use an enum as a template value argument, the name of the enum gets mangled into the template name. Which is really cool, it's a shame it doesn't work properly.
Ideally, integral template arguments would use the same lookup rules as for integral function arguments, rather than the "everything's an int" rule from C++. Right now, we have a curious mix of the two, and you can generate some pretty interesting bugs.
February 07, 2006
"Don Clugston" <dac@nospam.com.au> wrote in message news:ds753m$2fve$1@digitaldaemon.com...
> The problem is, the type used inside the mangled name seems to depend on how the template is SPECIALISED, but not on how it is DECLARED. So this example fails:
>
> -------
>     template frog(int F)
>     {
>         const int frog = 2;
>     }
>
>     template frog(int F:'A')
>     {
>         const int frog = 3;
>     }
>     static assert( frog!('A')==3);
> ---------
> It fails because the second template is not actually a specialisation of the first one!

It fails because frog!('A') passes 'A' of type 'char'. The specialization frog(int F:'A') means the parameter is of type 'int' with a value of '65', because the 'A' specialization is implicitly converted to 'int'. 'char' is not an 'int', so the specialization is not used.


> But, the following code works:
> ------
>     template frog(char F)
>     {
>         const int frog = 2;
>     }
>
>     template frog(char F:'A')
>     {
>         const int frog = 3;
>     }
>     static assert( frog!('A')==3);
> ------

That works because 'A' is a char and matches the char type of the specialization.

> Ideally, integral template arguments would use the same lookup rules as for integral function arguments, rather than the "everything's an int" rule from C++. Right now, we have a curious mix of the two, and you can generate some pretty interesting bugs.

Template matching in D follows the rule that specialization of values must match exactly. If there is more than one template of a given name, they aren't promoted to int. Also, for types, if there is more than one match the rule of "most specialized" is applied to disambiguate.


February 07, 2006
"Don Clugston" <dac@nospam.com.au> wrote in message news:ds753m$2fve$1@digitaldaemon.com...
> I think the mangling rule should be:
> TemplateArg:
>     T Type
>     V ValueArg
>     S LName
>
> ValueArg:
>    Type Value

You're right, the docs are wrong, and I'll fix them.

> and Value is Number for positive integral types, N Number for negative
> ints, hex digits for real/ireals, 2 x hex digits for creals,
> hex digits for strings. This is almost, but not quite, what happens now.

I thought it was what's happening now?


February 08, 2006
Walter Bright wrote:
> "Don Clugston" <dac@nospam.com.au> wrote in message news:ds753m$2fve$1@digitaldaemon.com...
>> I think the mangling rule should be:
>> TemplateArg:
>>     T Type
>>     V ValueArg
>>     S LName
>>
>> ValueArg:
>>    Type Value
> 
> You're right, the docs are wrong, and I'll fix them.
> 
>> and Value is Number for positive integral types, N Number for negative ints, hex digits for real/ireals, 2 x hex digits for creals,
>> hex digits for strings. This is almost, but not quite, what happens now.
> 
> I thought it was what's happening now? 
That's what happens for specialisations. But it doesn't happen for the non-specialised template. The non-specialised one always gets the type value int ("Vi"), regardless of what type was used in the declaration. Specialisations get the type from the declaration.
The following code doesn't compile, because the first two templates are both template frog(int). But, if you comment out the first two, there's no conflict (you can overload specialisations, but not the template they are specialising!).

----------------------------
template frog(char F)
{
    const int frog = 1;
}

template frog(int F)
{
    const int frog = 2;
}

template frog(char F: 'A')
{
    const int frog = 3;
}

template frog(int F: 65)
{
    const int frog = 4;
}

static assert( frog!('A')==3);
static assert( frog!(65)==4);


February 11, 2006
Don Clugston schrieb am 2006-02-08:
> Walter Bright wrote:
>> "Don Clugston" <dac@nospam.com.au> wrote in message news:ds753m$2fve$1@digitaldaemon.com...
>>> I think the mangling rule should be:
>>> TemplateArg:
>>>     T Type
>>>     V ValueArg
>>>     S LName
>>>
>>> ValueArg:
>>>    Type Value
>> 
>> You're right, the docs are wrong, and I'll fix them.
>> 
>>> and Value is Number for positive integral types, N Number for negative
>>> ints, hex digits for real/ireals, 2 x hex digits for creals,
>>> hex digits for strings. This is almost, but not quite, what happens now.
>> 
>> I thought it was what's happening now?
> That's what happens for specialisations. But it doesn't happen for the
> non-specialised template. The non-specialised one always gets the type
> value int ("Vi"), regardless of what type was used in the declaration.
> Specialisations get the type from the declaration.
> The following code doesn't compile, because the first two templates are
> both template frog(int). But, if you comment out the first two, there's
> no conflict (you can overload specialisations, but not the template they
> are specialising!).
>
> ----------------------------
> template frog(char F)
> {
>      const int frog = 1;
> }
>
> template frog(int F)
> {
>      const int frog = 2;
> }
>
> template frog(char F: 'A')
> {
>      const int frog = 3;
> }
>
> template frog(int F: 65)
> {
>      const int frog = 4;
> }
>
> static assert( frog!('A')==3);
> static assert( frog!(65)==4);

Added to DStress as http://dstress.kuehne.cn/run/t/template_27_A.d http://dstress.kuehne.cn/run/t/template_27_B.d http://dstress.kuehne.cn/run/t/template_27_C.d http://dstress.kuehne.cn/run/t/template_27_D.d

Thomas