www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Mingling string and identifier namespaces in nested extern(C++) decls

reply Max Samukha <maxsamukha gmail.com> writes:
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?
Sep 07 2019
next sibling parent Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
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. - Jonathan M Davis
Sep 07 2019
prev sibling parent Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
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
Sep 07 2019