`ref T` should be a type!!

Manu turkeyman at gmail.com
Sat Apr 6 22:52:28 UTC 2019


On Sat, Apr 6, 2019 at 8:30 AM Herb Sutter via Digitalmars-d
<digitalmars-d at puremagic.com> wrote:
>
> On Thursday, 4 April 2019 at 17:25:05 UTC, Andrei Alexandrescu
> wrote:
> > On 4/4/19 1:20 PM, Manu wrote:
> >> Also, FWIW, I think this is a fairly recent change (ie, last 5
> >> years).
> >
> > Good to know, thanks! Found this, too:
> >
> > https://stackoverflow.com/questions/32447978/odd-vs-name-mangling-behavior/32448512
> >
> > I'll email Herb.
>
> Andrei sent me mail and I did a little digging. Much of the
> following is courtesy Jonathan Caves (thanks Jon!).
>
> Pasting what I sent to Andrei with light edits:
>
>
> Short answer: Yes, but most C++ code won't (and doesn't) notice
> because to see the different mangling you have to declare the
> function differently in two translation units, *and* have
> different "first" declarations in those TUs. So this is invisible
> for any function you declare in a shared header (because everyone
> sees the same first declaration). And it's invisible when you
> declare without top-level const and then define with top-level
> const on a parameter (because everyone uses the first
> declaration).
>
>
> Longer answer: Yes, this is a long standing known issue – our
> name decorator was developed long before C++98 codified a lot of
> stuff.
>
> Note that there are two mangling issues involved that come up in
> your example (or minor variations of it): [dcl.fct]/5 says that
> function parameters ignore top-level const and treat [] as *:
>
> > After determining the type of each parameter, any parameter of
> > type
> > “array of T” or of function type T is adjusted to be “pointer
> > to T”.
> > After producing the list of parameter types, any top-level
> > cv-qualifiers
> > modifying a parameter type are deleted when forming the
> > function type.
>
> So these are supposed to be equivalent redeclarations of f and g:
>
> ~~~
> // Case 1
> void f(int);
> void f(int const); // same, redeclaration
>
> // Case 2
> void g(int*);
> void g(int[]); // same, redeclaration
> ~~~
>
> And in VC++ they are correctly equivalent, in the language.
> However, for name mangling, VC++ selects mangling based on the
> first declaration it seems, and it does mangle each of these
> pairs differently, so if two TUs have different first
> declarations of each of f and g, they can’t link.
>
> Again, to make this actually visible to users, they have to see
> different *first* declarations. For starters that means they’re
> not using a shared header.
>
> I understand that someone you know found it caused trouble with
> linking foreign code with C++, though presumably that’s because
> they had to write their own declaration by hand (in C++, or in
> the other language)? I’ve mostly seen that sort of thing when
> people have to write their own declarations, and in those cases
> they also had general fragility (e.g., writing int vs long, that
> sort of thing – because they have to be careful to get the
> declarations exactly right because they’re writing them manually,
> same trouble that Java JNI and .NET P/Invoke have in general, you
> have to make the parameters perfect).
>
> The worry about ‘fixing’ the name decorator is that it would be
> an ABI breaking change and so we have always be reticent in
> making any changes. That said, if we had customer examples that
> this was causing serious problems, we’d consider it. If you have
> production examples you could share or link to that would be
> helpful. Mostly, we don’t hear about this and I couldn’t find a
> report of it in our current online bug tracking systems (but I
> may have missed it) – most people are like you and rarely notice
> it even though it’s been like this for ~25 years. :) Because you
> have to be writing code in a fairly special way, effectively
> writing somebody else's function declaration by hand instead of
> using the .h they provided, and write it differently than in that
> .h, to be able to notice.

Thanks for the background.

For my effort (binding to STL), a bigger problem with MSVC
compatibility isn't that this mangling is weird (I have an awkward
solution in this case), it's that the MS C++ runtime ABI has
historically been somewhat volatile.
The significant ABI-breaking change was when allocator<T>::destroy()
was changed from `T*` to `T* const`, which appears to have happened
perhaps vc2013->2015? (I don't have those old headers on my system
anymore to check). There are numerous other cases of ABI breakage, but
this one happened to introduce `* const`, which I couldn't express.
Fortunately, it seems VS2015 and onward has made greater efforts
towards ABI stability, so I plan to simply deprecate distant
backwards-compatibility, and hope for a continued commitment from your
side ;)

For future reference, if you're making this decision about your ABI
when authoring the runtime; for foreign languages trying to link to
C++, I expect `T*` is generally much simpler. I suspect many FFI's
would have trouble with `* const`, and D is one such case.
We cross-language linker-er's would certainly appreciate trying to
avoid `* const` in public ABI's since MSVC has this odd mangling rule.



More information about the Digitalmars-d mailing list