A bug was filed against Clang claiming that we mangle a particular symbol 
differently from GCC:
  https://llvm.org/bugs/show_bug.cgi?id=24794

Basically, it comes down to this:

namespace foo {
  class V {};
}

namespace baz {
  template <class _Ty>
  struct is_enum {
    static const bool value = __is_enum(_Ty);
  };

  template<bool _Test, class _Ty = void>
  struct enable_if {
  };

  template<class _Ty>
  struct enable_if < true, _Ty > {
    typedef _Ty type;
  };

  template <class T>
  typename enable_if< !is_enum< T >::value, void>::type
  Conv(T &x, int *v);
}

int main() {
  int v;
  int i;
  baz::Conv(v, &i);
}

Clang mangles this template specialization as:
  _ZN3baz4ConvIiEENS_9enable_ifIXntsr7is_enumIT_EE5valueEvE4typeERS2_Pi
GCC mangles it as:
  _ZN3baz4ConvIiEENS_9enable_ifIXntsrNS_7is_enumIT_EE5valueEvE4typeERS3_Pi

The key question for this list is the mangling of
  is_enum< T >::value
as either (Clang):
  sr7is_enumIT_EE5valueE
or (GCC, and perhaps EDG):
  srNS_7is_enumIT_EE5valueE

This expression is an unresolved-name.  In the current spec, we have:

  <unresolved-name> ::= [gs] <base-unresolved-name>                     # 
Production #1: x or (with "gs") ::x
                    ::= sr <unresolved-type> <base-unresolved-name>     # 
Production #2: T::x / decltype(p)::x
                    ::= srN <unresolved-type> <unresolved-qualifier-level>+ E 
<base-unresolved-name>
                                                                        # 
Production #3: T::N::x /decltype(p)::N::x
                    ::= [gs] sr <unresolved-qualifier-level>+ E 
<base-unresolved-name>  
                                                                        # 
Production #4: A::x, N::y, A<T>::z; "gs" means leading "::"

  <unresolved-type> ::= <template-param>
                    ::= <decltype>
                    ::= <substitution>

  <unresolved-qualifier-level> ::= <simple-id>
  <base-unresolved-name> ::= <simple-id>
  <simple-id> ::= <source-name> [ <template-args> ]

Clang is looking at this and saying that it’s not rooted in a template-param or 
a decltype, so it’s not rooted in an unresolved-type, so it has to be mangled 
using the fourth production of unresolved-name.  GCC appears to be looking at 
it and saying that it has a substitution for something in the prefix, namely 
the (implicit) “baz::”, so the unresolved-type should be mangled using one of 
the second or third productions; since there’s another level of prefix 
(“is_enum<T>::”) before the final base-unresolved-name, it has to use the third 
production, srN.

When reasoning about this to myself, it occurred to me that I was arguing based 
on something that’s not actually spelled out in the spec.  Specifically, it 
seems right to me that the general intent of <substitution> is that it only 
ever shortens something that *could* otherwise be mangled by the current 
production.  For most cases of <substitution>, this is a distinction without a 
difference, because the production is only used in specific places that limit 
what entities can appear there, and all those entities can be mangled there; 
for example, that’s true of all the places where <prefix> is used.  But 
<unresolved-type> is different, because there are many possible unresolvable 
prefixes that are substitution candidates but neither a template-parameter or a 
decltype.  In our example, “baz::” isn’t even a type; and if this conversion 
function didn’t happen to be written in that namespace, there wouldn’t be an 
existing substitution for it, and the only legal mangling would use production 
#4.

Now, if I were designing this mangling from scratch today, I’d probably say 
that any resolvable entities in the prefix should actually be mangled as normal 
entities, instead of textually, and of course that would also make them 
substitution candidates.  That is, “baz", "baz::is_enum”, and “baz::is_enum<T>” 
would all be legit substitutions here, and if they weren’t substituted they’d 
at least be mangled as properly-resolved entities, so that (e.g.) a function 
where is_enum resolved to be an entity in a different namespace would actually 
be mangled differently.  But that’s not how I read the specification.

Unfortunately, this might be a serious compatibility problem.  What do other 
compilers do?  What’s the general feeling about this?

John.
_______________________________________________
cxx-abi-dev mailing list
[email protected]
http://sourcerytools.com/cgi-bin/mailman/listinfo/cxx-abi-dev

Reply via email to