Mingling string and identifier namespaces in nested extern(C++) decls

Jonathan M Davis newsgroup.d at jmdavisprog.com
Sat Sep 7 23:28:24 UTC 2019


On Saturday, September 7, 2019 2:18:40 PM MDT Jonathan M Davis via 
Digitalmars-d-learn wrote:
> On Saturday, September 7, 2019 8:53:54 AM MDT Max Samukha via
> Digitalmars-d-
> learn wrote:
> > extern(C++, "ns1") {
> >
> >   extern(C++, ns2) {
> >
> >       extern(C++, "ns3") {
> >
> >           extern(C++, ns4) {
> >
> >               void foo();
> >
> >           }
> >
> >       }
> >
> >   }
> >
> > }
> >
> > pragma(msg, foo.mangleof); // _ZN3ns23ns43ns13ns33fooEv
> >
> > That produces 'ns2::ns4::ns1::ns3::foo' path instead of the
> > intuitively expected 'ns1::ns2::ns3::ns4::foo'. The identifier
> > namespaces are grouped before the string ones. Bug or feature?
>
> Given that the string version of extern(C++) is supposed to only affect
> mangling, whereas the other version does some other weird stuff, I'm not
> sure that you can really expect something sane if you try to mix them.
> That being said, unless the language disallows mixing them, the compiler
> should be doing something at least semi-sane. Either way, I don't see how
> having the result be anything other than ns1:ns2:ns3:ns4 is defensible.
> The type of weirdness that I would expect would resolve around the kind
> of issues that led to the string version being added in the first place
> (e.g. having to put the entire namespace in a single module). I'd suggest
> that you report it as a bug. It wouldn't surprise me if dmd doesn't even
> have any tests that try to mix the two types of extern(C++), since that
> really wasn't an intended use case. If anything, I expect that the hope
> was that the non-string version would eventually be deprecated, though I
> wouldn't bet on that actually happening.

Actually, thinking on this further, I would have thought that only the
extern(C++, ns4) would be applied. No other D attributes have any kind of
nesting. Applying incompatible attributes either results in one overriding
the other or in an error (usually, one overrides the other when attributes
are mass-applied, whereas you get an error if you put them directly on the
symbol).

If we allow nesting like this with extern(C++), then I would expect that the
nesting would work in the same order as you'd get in C++, which would be
ns1:ns2:ns3:ns4 in this case, but I would have expected that you'd have to
apply the entire namespace in one go rather than have multiple extern(C++)
declarations - e.g. extern(C++, "ns1:ns2:ns3:ns4") or
extern(C++, ns1, ns2, ns3, ns4) for the non-string version IIRC (I've
avoided the non-string extern(C++) like the plague though, since it makes no
sense, and fortunately, most of the C++ that I've interacted with from D has
not had namespaces).

In any case, I would consider the current behavior to be nonsensical, and I
have a hard time believing that it's on purpose. With that example, I would
expect that you'd either get only ns4 applied or that you'd get
ns1:ns2:ns3:ns4. Getting only ns4 would be consistent with the rest of D,
whereas ns1:ns2:ns3:ns4 would be more consistent with what someone would
expect if they were coming from C++ and translating the C++ declarations to
D declarations directly.

- Jonathan M Davis





More information about the Digitalmars-d-learn mailing list