www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - Name mangling is broken for integral template value arguments.

reply Don Clugston <dac nospam.com.au> writes:
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.
Feb 06 2006
next sibling parent "Walter Bright" <newshound digitalmars.com> writes:
"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.
Feb 07 2006
prev sibling parent reply "Walter Bright" <newshound digitalmars.com> writes:
"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?
Feb 07 2006
parent reply Don Clugston <dac nospam.com.au> writes:
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?

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);
Feb 08 2006
parent Thomas Kuehne <thomas-dloop kuehne.cn> writes:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

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?

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 -----BEGIN PGP SIGNATURE----- iD8DBQFD7a503w+/yD4P9tIRAlZTAJ4oRW0uo5PHribSHpIYNxfLkvugIwCfcARh fc5wFa4QxiGLRex7FPij4ew= =J5Vq -----END PGP SIGNATURE-----
Feb 11 2006