On Sat, Apr 20, 2013 at 2:23 AM, Rainer Schuetze <r.sagitario@gmx.de> wrote:
On 18.04.2013 15:22, Daniel Murphy wrote:
Hi all,

I have come across one strange case where dmd and dmc produce different
mangling for seemingly identical declarations.

D:
extern(C++) const(const(bool)*) gc_pi1; // mangled as ?gc_pi1@@3PB_NB

C++:
extern bool const * const gc_pi1; // mangled as ?gc_pi1@@3QB_NB

So we have '[PQ]B_NB' which translates to '[pointer/const pointer] const
bool const' where both of the const modifiers (for some reason) apply to
the bool, not the pointer.

If I understand Agner Fog (http://www.agner.org/optimize/calling_conventions.pdf) correctly, "QB_NB" is parsed as QBtype with "QB" translating to "type *const" and type "_NB" translating to "const bool". So the const modifiers bind to different entities.


Further tests show the rightmost cv-modifier is not bound to the final target type, but the first target type (target of the outmost indirection).  Agner's manual seems to imply that the rightmost cv-modifier is the storage class of the declaration itself (although it doesn't explicitly say this).

(All compiled with dmc)

extern bool const * const less_11; // ?less_11@@3 Q B _N B
extern bool const *       less_10; // ?less_10@@3 P B _N B
extern bool       * const less_01; // ?less_01@@3 Q A _N A
extern bool       *       less_00; // ?less_00@@3 P A _N A

extern bool const * const * const more_111; // ?more_111@@3 Q B Q B _N B
extern bool const * const *       more_110; // ?more_110@@3 P B Q B _N B
extern bool const *       * const more_101; // ?more_101@@3 Q A P B _N A
extern bool const *       *       more_100; // ?more_100@@3 P A P B _N A
extern bool       * const * const more_011; // ?more_011@@3 Q B Q A _N B
extern bool       * const *       more_010; // ?more_010@@3 P B Q A _N B
extern bool       *       * const more_001; // ?more_001@@3 Q A P A _N A
extern bool       *       *       more_000; // ?more_000@@3 P A P A _N A

extern bool const * const * const * const * const strange_11111; // ?strange_11111@@3 Q B Q B Q B Q B _N B
extern bool const * const * const * const *       strange_11110; // ?strange_11110@@3 P B Q B Q B Q B _N B
extern bool const * const * const *       * const strange_11101; // ?strange_11101@@3 Q A P B Q B Q B _N A
extern bool const * const * const *       *       strange_11100; // ?strange_11100@@3 P A P B Q B Q B _N A
extern bool const * const *       * const * const strange_11011; // ?strange_11011@@3 Q B Q A P B Q B _N B
extern bool const * const *       * const *       strange_11010; // ?strange_11010@@3 P B Q A P B Q B _N B
extern bool const * const *       *       * const strange_11001; // ?strange_11001@@3 Q A P A P B Q B _N A
extern bool const * const *       *       *       strange_11000; // ?strange_11000@@3 P A P A P B Q B _N A
extern bool const *       * const * const * const strange_10111; // ?strange_10111@@3 Q B Q B Q A P B _N B
extern bool const *       * const * const *       strange_10110; // ?strange_10110@@3 P B Q B Q A P B _N B
extern bool const *       * const *       * const strange_10101; // ?strange_10101@@3 Q A P B Q A P B _N A
extern bool const *       * const *       *       strange_10100; // ?strange_10100@@3 P A P B Q A P B _N A
extern bool const *       *       * const * const strange_10011; // ?strange_10011@@3 Q B Q A P A P B _N B
extern bool const *       *       * const *       strange_10010; // ?strange_10010@@3 P B Q A P A P B _N B
extern bool const *       *       *       * const strange_10001; // ?strange_10001@@3 Q A P A P A P B _N A
extern bool const *       *       *       *       strange_10000; // ?strange_10000@@3 P A P A P A P B _N A
extern bool       * const * const * const * const strange_01111; // ?strange_01111@@3 Q B Q B Q B Q A _N B
extern bool       * const * const * const *       strange_01110; // ?strange_01110@@3 P B Q B Q B Q A _N B
extern bool       * const * const *       * const strange_01101; // ?strange_01101@@3 Q A P B Q B Q A _N A
extern bool       * const * const *       *       strange_01100; // ?strange_01100@@3 P A P B Q B Q A _N A
extern bool       * const *       * const * const strange_01011; // ?strange_01011@@3 Q B Q A P B Q A _N B
extern bool       * const *       * const *       strange_01010; // ?strange_01010@@3 P B Q A P B Q A _N B
extern bool       * const *       *       * const strange_01001; // ?strange_01001@@3 Q A P A P B Q A _N A
extern bool       * const *       *       *       strange_01000; // ?strange_01000@@3 P A P A P B Q A _N A
extern bool       *       * const * const * const strange_00111; // ?strange_00111@@3 Q B Q B Q A P A _N B
extern bool       *       * const * const *       strange_00110; // ?strange_00110@@3 P B Q B Q A P A _N B
extern bool       *       * const *       * const strange_00101; // ?strange_00101@@3 Q A P B Q A P A _N A
extern bool       *       * const *       *       strange_00100; // ?strange_00100@@3 P A P B Q A P A _N A
extern bool       *       *       * const * const strange_00011; // ?strange_00011@@3 Q B Q A P A P A _N B
extern bool       *       *       * const *       strange_00010; // ?strange_00010@@3 P B Q A P A P A _N B
extern bool       *       *       *       * const strange_00001; // ?strange_00001@@3 Q A P A P A P A _N A
extern bool       *       *       *       *       strange_00000; // ?strange_00000@@3 P A P A P A P A _N A

 
Is dmd incorrectly printing 'P' instead of 'Q' or have I missed something?

I suspect dmd might be omitting the transitive "const" to allow leaving "const char *" as is instead of requiring "const(char)*" when translating C++ headers to D.


Interesting.  I'm not sure that's a good idea.
 


Thanks,
Daniel.

PS If anybody with msvc installed could try this I would be very grateful.

cl 15.0 and 16.0 (from VS2008 and VS2010) mangle it the same as dmc:

error LNK2019: unresolved external symbol "bool const * const gc_pi1" (?gc_pi1@@3QB_NB) referenced in function _main

Thanks, I'm going to classify dmd's behavior as a bug.