ASTNameGenerator mangles __uint16_identity in extern C statement

We are in the process to switch to using the ASTNameGenerator class to generate mangled names in our Clang-based project.
While things work smoothly, we found a discrepancy between GCC and Clang, and we are unsure what is the correct behavior, or if both are correct.

Given the snippet

extern "C" {
typedef unsigned short int __uint16_t;
static __inline __uint16_t __uint16_identity(__uint16_t __x) { return __x; }

Clang’s ASTNameGenerator returns the mangled name _ZL17__uint16_identityt for that function.
Our code is

std::vector<std::string> getMangledName(clang::NamedDecl const *const nd) {
  clang::ASTNameGenerator NG(nd->getASTContext());
  if (llvm::isa<clang::CXXRecordDecl>(nd) || llvm::isa<clang::CXXMethodDecl>(nd) ||
      llvm::isa<clang::ObjCInterfaceDecl>(nd) || llvm::isa<clang::ObjCImplementationDecl>(nd)) {
    return NG.getAllManglings(nd);
  return {NG.getName(nd)};

GCC on the other hand, returns the C-like name __uint16_identity, that I would expect to be generated for that function in that context.

Your help is greatly appreciated.

Since __uint16_identity has internal linkage, both the clang and gcc behaviors are permissible; the Itanium ABI specification doesn’t apply. I believe Clang’s use of L following _Z to name symbols with internal linkage is an extension of the Itanium ABI.

I don’t know if it is intentional that Clang deviates from gcc behavior though. The use of a mangled name reserved for symbols with internal linkage does have the benefit of avoiding name collisions with symbols with external linkage in other TUs for linkers that don’t support other means of restricting symbol visibility.

If you want to make a local change, take a look at MangleContext::shouldMangleDeclName() and ItaniumMangleContextImpl::isUniqueInternalLinkageDecl().

1 Like