"llvm/lib/git@repo.hca.bsc.es:rferrer/llvm-epi-0.8.git" did not exist on "042d56230e4547ad8f52d9f316695c501befdf52"
Newer
Older
//===--- Mangle.cpp - Mangle C++ Names --------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Implements C++ name mangling according to the Itanium C++ ABI,
// which is used in GCC 3.2 and newer (and many compilers that are
// ABI-compatible with GCC):
//
// http://www.codesourcery.com/public/cxx-abi/abi.html
//
//===----------------------------------------------------------------------===//
#include "Mangle.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
Anders Carlsson
committed
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ExprCXX.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/raw_ostream.h"
John McCall
committed
#include "llvm/Support/ErrorHandling.h"
using namespace clang;
namespace {
class VISIBILITY_HIDDEN CXXNameMangler {
Anders Carlsson
committed
MangleContext &Context;
llvm::raw_ostream &Out;
Anders Carlsson
committed
const CXXMethodDecl *Structor;
unsigned StructorType;
Anders Carlsson
committed
CXXCtorType CtorType;
Anders Carlsson
committed
llvm::DenseMap<uintptr_t, unsigned> Substitutions;
public:
Anders Carlsson
committed
CXXNameMangler(MangleContext &C, llvm::raw_ostream &os)
Anders Carlsson
committed
: Context(C), Out(os), Structor(0), StructorType(0) { }
bool mangle(const NamedDecl *D);
void mangleCalloffset(int64_t nv, int64_t v);
void mangleThunk(const FunctionDecl *FD, int64_t nv, int64_t v);
void mangleCovariantThunk(const FunctionDecl *FD,
int64_t nv_t, int64_t v_t,
void mangleGuardVariable(const VarDecl *D);
Anders Carlsson
committed
void mangleCXXVtable(const CXXRecordDecl *RD);
void mangleCXXCtorVtable(const CXXRecordDecl *RD, int64_t Offset,
const CXXRecordDecl *Type);
void mangleCXXRtti(QualType Ty);
Anders Carlsson
committed
void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type);
Anders Carlsson
committed
void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type);
Anders Carlsson
committed
Anders Carlsson
committed
private:
bool mangleSubstitution(const NamedDecl *ND);
Anders Carlsson
committed
bool mangleSubstitution(QualType T);
bool mangleSubstitution(uintptr_t Ptr);
bool mangleStandardSubstitution(const NamedDecl *ND);
void addSubstitution(const NamedDecl *ND) {
Anders Carlsson
committed
ND = cast<NamedDecl>(ND->getCanonicalDecl());
addSubstitution(reinterpret_cast<uintptr_t>(ND));
}
Anders Carlsson
committed
void addSubstitution(QualType T);
void addSubstitution(uintptr_t Ptr);
Anders Carlsson
committed
Anders Carlsson
committed
bool mangleFunctionDecl(const FunctionDecl *FD);
void mangleFunctionEncoding(const FunctionDecl *FD);
void mangleName(const NamedDecl *ND);
void mangleName(const TemplateDecl *TD,
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs);
void mangleUnqualifiedName(const NamedDecl *ND);
Anders Carlsson
committed
void mangleUnscopedName(const NamedDecl *ND);
Anders Carlsson
committed
void mangleUnscopedTemplateName(const TemplateDecl *ND);
void mangleSourceName(const IdentifierInfo *II);
void mangleLocalName(const NamedDecl *ND);
void mangleNestedName(const NamedDecl *ND);
void mangleNestedName(const TemplateDecl *TD,
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs);
void manglePrefix(const DeclContext *DC);
Anders Carlsson
committed
void mangleTemplatePrefix(const TemplateDecl *ND);
void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity);
void mangleQualifiers(Qualifiers Quals);
void mangleType(QualType T);
John McCall
committed
// Declare manglers for every type class.
#define ABSTRACT_TYPE(CLASS, PARENT)
#define NON_CANONICAL_TYPE(CLASS, PARENT)
#define TYPE(CLASS, PARENT) void mangleType(const CLASS##Type *T);
#include "clang/AST/TypeNodes.def"
void mangleType(const TagType*);
void mangleBareFunctionType(const FunctionType *T,
bool MangleReturnType);
Anders Carlsson
committed
void mangleCXXCtorType(CXXCtorType T);
Anders Carlsson
committed
void mangleCXXDtorType(CXXDtorType T);
void mangleTemplateArgs(const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs);
void mangleTemplateArgumentList(const TemplateArgumentList &L);
void mangleTemplateArgument(const TemplateArgument &A);
void mangleTemplateParameter(unsigned Index);
};
}
Anders Carlsson
committed
static bool isInCLinkageSpecification(const Decl *D) {
D = D->getCanonicalDecl();
for (const DeclContext *DC = D->getDeclContext();
Anders Carlsson
committed
!DC->isTranslationUnit(); DC = DC->getParent()) {
if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC))
Anders Carlsson
committed
return Linkage->getLanguage() == LinkageSpecDecl::lang_c;
Chris Lattner
committed
}
Anders Carlsson
committed
return false;
}
Anders Carlsson
committed
bool CXXNameMangler::mangleFunctionDecl(const FunctionDecl *FD) {
// Clang's "overloadable" attribute extension to C/C++ implies name mangling
// (always) as does passing a C++ member function and a function
// whose name is not a simple identifier.
if (!FD->hasAttr<OverloadableAttr>() && !isa<CXXMethodDecl>(FD) &&
FD->getDeclName().isIdentifier()) {
// C functions are not mangled, and "main" is never mangled.
Anders Carlsson
committed
if (!Context.getASTContext().getLangOptions().CPlusPlus || FD->isMain())
return false;
// No mangling in an "implicit extern C" header.
if (FD->getLocation().isValid() &&
Anders Carlsson
committed
Context.getASTContext().getSourceManager().
isInExternCSystemHeader(FD->getLocation()))
return false;
// No name mangling in a C linkage specification.
if (isInCLinkageSpecification(FD))
return false;
}
// If we get here, mangle the decl name!
Out << "_Z";
mangleFunctionEncoding(FD);
return true;
}
Anders Carlsson
committed
bool CXXNameMangler::mangle(const NamedDecl *D) {
// Any decl can be declared with __asm("foo") on it, and this takes precedence
// over all other naming in the .o file.
Argyrios Kyrtzidis
committed
if (const AsmLabelAttr *ALA = D->getAttr<AsmLabelAttr>()) {
Anders Carlsson
committed
// If we have an asm name, then we use it as the mangling.
Out << '\01'; // LLVM IR Marker for __asm("foo")
Out << ALA->getLabel();
return true;
}
Anders Carlsson
committed
// <mangled-name> ::= _Z <encoding>
// ::= <data name>
// ::= <special-name>
// FIXME: Actually use a visitor to decode these?
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
return mangleFunctionDecl(FD);
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
Anders Carlsson
committed
if (!Context.getASTContext().getLangOptions().CPlusPlus ||
isInCLinkageSpecification(D) ||
D->getDeclContext()->isTranslationUnit())
Out << "_Z";
mangleName(VD);
return true;
}
Anders Carlsson
committed
return false;
}
void CXXNameMangler::mangleCXXCtor(const CXXConstructorDecl *D,
Anders Carlsson
committed
CXXCtorType Type) {
Anders Carlsson
committed
assert(!Structor && "Structor already set!");
Structor = D;
StructorType = Type;
Anders Carlsson
committed
mangle(D);
}
void CXXNameMangler::mangleCXXDtor(const CXXDestructorDecl *D,
Anders Carlsson
committed
CXXDtorType Type) {
assert(!Structor && "Structor already set!");
Structor = D;
StructorType = Type;
Anders Carlsson
committed
mangle(D);
}
Anders Carlsson
committed
void CXXNameMangler::mangleCXXVtable(const CXXRecordDecl *RD) {
// <special-name> ::= TV <type> # virtual table
Out << "_ZTV";
Anders Carlsson
committed
mangleName(RD);
}
void CXXNameMangler::mangleCXXVTT(const CXXRecordDecl *RD) {
// <special-name> ::= TT <type> # VTT structure
Out << "_ZTT";
mangleName(RD);
}
void CXXNameMangler::mangleCXXCtorVtable(const CXXRecordDecl *RD,
int64_t Offset,
const CXXRecordDecl *Type) {
// <special-name> ::= TC <type> <offset number> _ <base type>
Out << "_ZTC";
mangleName(RD);
Out << Offset;
Out << "_";
mangleName(Type);
}
void CXXNameMangler::mangleCXXRtti(QualType Ty) {
// <special-name> ::= TI <type> # typeinfo structure
Out << "_ZTI";
mangleType(Ty);
void CXXNameMangler::mangleGuardVariable(const VarDecl *D) {
// <special-name> ::= GV <object name> # Guard variable for one-time
// # initialization
Out << "_ZGV";
mangleName(D);
}
void CXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) {
// <encoding> ::= <function name> <bare-function-type>
mangleName(FD);
// Whether the mangling of a function type includes the return type depends on
// the context and the nature of the function. The rules for deciding whether
// the return type is included are:
// 1. Template functions (names or types) have return types encoded, with
// the exceptions listed below.
// 2. Function types not appearing as part of a function name mangling,
// e.g. parameters, pointer types, etc., have return type encoded, with the
// exceptions listed below.
// 3. Non-template function names do not have return types encoded.
//
// The exceptions mentioned in (1) and (2) above, for which the return type is
// never included, are
// 1. Constructors.
// 2. Destructors.
// 3. Conversion operator functions, e.g. operator int.
bool MangleReturnType = false;
Anders Carlsson
committed
if (FunctionTemplateDecl *PrimaryTemplate = FD->getPrimaryTemplate()) {
if (!(isa<CXXConstructorDecl>(FD) || isa<CXXDestructorDecl>(FD) ||
isa<CXXConversionDecl>(FD)))
MangleReturnType = true;
// Mangle the type of the primary template.
FD = PrimaryTemplate->getTemplatedDecl();
}
// Do the canonicalization out here because parameter types can
// undergo additional canonicalization (e.g. array decay).
FunctionType *FT = cast<FunctionType>(Context.getASTContext()
.getCanonicalType(FD->getType()));
mangleBareFunctionType(FT, MangleReturnType);
}
static bool isStdNamespace(const DeclContext *DC) {
if (!DC->isNamespace() || !DC->getParent()->isTranslationUnit())
return false;
const NamespaceDecl *NS = cast<NamespaceDecl>(DC);
const IdentifierInfo *II = NS->getOriginalNamespace()->getIdentifier();
return II && II->isStr("std");
}
static const TemplateDecl *
isTemplate(const NamedDecl *ND, const TemplateArgumentList *&TemplateArgs) {
// Check if we have a function template.
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)){
if (const TemplateDecl *TD = FD->getPrimaryTemplate()) {
TemplateArgs = FD->getTemplateSpecializationArgs();
return TD;
// Check if we have a class template.
if (const ClassTemplateSpecializationDecl *Spec =
dyn_cast<ClassTemplateSpecializationDecl>(ND)) {
TemplateArgs = &Spec->getTemplateArgs();
return Spec->getSpecializedTemplate();
void CXXNameMangler::mangleName(const NamedDecl *ND) {
// <name> ::= <nested-name>
// ::= <unscoped-name>
// ::= <unscoped-template-name> <template-args>
Anders Carlsson
committed
// ::= <local-name>
//
const DeclContext *DC = ND->getDeclContext();
Anders Carlsson
committed
while (isa<LinkageSpecDecl>(DC))
DC = DC->getParent();
if (DC->isTranslationUnit() || isStdNamespace(DC)) {
// Check if we have a template.
const TemplateArgumentList *TemplateArgs = 0;
Anders Carlsson
committed
if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) {
mangleUnscopedTemplateName(TD);
mangleTemplateArgumentList(*TemplateArgs);
return;
}
mangleUnscopedName(ND);
return;
}
if (isa<FunctionDecl>(DC)) {
mangleLocalName(ND);
void CXXNameMangler::mangleName(const TemplateDecl *TD,
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs) {
const DeclContext *DC = TD->getDeclContext();
while (isa<LinkageSpecDecl>(DC)) {
assert(cast<LinkageSpecDecl>(DC)->getLanguage() ==
LinkageSpecDecl::lang_cxx && "Unexpected linkage decl!");
DC = DC->getParent();
}
if (DC->isTranslationUnit() || isStdNamespace(DC)) {
Anders Carlsson
committed
mangleUnscopedTemplateName(TD);
mangleTemplateArgs(TemplateArgs, NumTemplateArgs);
} else {
mangleNestedName(TD, TemplateArgs, NumTemplateArgs);
}
}
Anders Carlsson
committed
void CXXNameMangler::mangleUnscopedName(const NamedDecl *ND) {
// <unscoped-name> ::= <unqualified-name>
// ::= St <unqualified-name> # ::std::
if (isStdNamespace(ND->getDeclContext()))
Out << "St";
mangleUnqualifiedName(ND);
}
Anders Carlsson
committed
void CXXNameMangler::mangleUnscopedTemplateName(const TemplateDecl *ND) {
Anders Carlsson
committed
// <unscoped-template-name> ::= <unscoped-name>
// ::= <substitution>
if (mangleSubstitution(ND))
mangleUnscopedName(ND->getTemplatedDecl());
Anders Carlsson
committed
}
void CXXNameMangler::mangleCalloffset(int64_t nv, int64_t v) {
// <call-offset> ::= h <nv-offset> _
// ::= v <v-offset> _
// <nv-offset> ::= <offset number> # non-virtual base override
// <v-offset> ::= <offset nubmer> _ <virtual offset number>
// # virtual base override, with vcall offset
if (v == 0) {
if (nv < 0) {
Out << "n";
nv = -nv;
}
Out << nv;
} else {
if (nv < 0) {
Out << "n";
nv = -nv;
}
Out << nv;
Out << "_";
if (v < 0) {
Out << "n";
v = -v;
}
Out << v;
}
Out << "_";
void CXXNameMangler::mangleThunk(const FunctionDecl *FD, int64_t nv,
int64_t v) {
// <special-name> ::= T <call-offset> <base encoding>
// # base is the nominal target function of thunk
mangleCalloffset(nv, v);
void CXXNameMangler::mangleCovariantThunk(const FunctionDecl *FD,
int64_t nv_t, int64_t v_t,
int64_t nv_r, int64_t v_r) {
// <special-name> ::= Tc <call-offset> <call-offset> <base encoding>
// # base is the nominal target function of thunk
// # first call-offset is 'this' adjustment
// # second call-offset is result adjustment
mangleCalloffset(nv_t, v_t);
mangleCalloffset(nv_r, v_r);
void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND) {
// <unqualified-name> ::= <operator-name>
// ::= <ctor-dtor-name>
// ::= <source-name>
DeclarationName Name = ND->getDeclName();
switch (Name.getNameKind()) {
case DeclarationName::Identifier: {
if (const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(ND)) {
if (NS->isAnonymousNamespace()) {
// This is how gcc mangles these names. It's apparently
// always '1', no matter how many different anonymous
// namespaces appear in a context.
Out << "12_GLOBAL__N_1";
break;
}
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
}
if (const IdentifierInfo *II = Name.getAsIdentifierInfo()) {
mangleSourceName(II);
break;
}
// We must have an anonymous struct.
const TagDecl *TD = cast<TagDecl>(ND);
if (const TypedefDecl *D = TD->getTypedefForAnonDecl()) {
assert(TD->getDeclContext() == D->getDeclContext() &&
"Typedef should not be in another decl context!");
assert(D->getDeclName().getAsIdentifierInfo() &&
"Typedef was not named!");
mangleSourceName(D->getDeclName().getAsIdentifierInfo());
break;
}
// Get a unique id for the anonymous struct.
uint64_t AnonStructId = Context.getAnonymousStructId(TD);
// Mangle it as a source name in the form
// [n] $_<id>
// where n is the length of the string.
llvm::SmallString<8> Str;
Str += "$_";
Str += llvm::utostr(AnonStructId);
Out << Str.size();
Out << Str.str();
break;
case DeclarationName::ObjCZeroArgSelector:
case DeclarationName::ObjCOneArgSelector:
case DeclarationName::ObjCMultiArgSelector:
assert(false && "Can't mangle Objective-C selector names here!");
break;
case DeclarationName::CXXConstructorName:
Anders Carlsson
committed
if (ND == Structor)
// If the named decl is the C++ constructor we're mangling, use the type
// we were given.
Anders Carlsson
committed
mangleCXXCtorType(static_cast<CXXCtorType>(StructorType));
Anders Carlsson
committed
else
// Otherwise, use the complete constructor name. This is relevant if a
// class with a constructor is declared within a constructor.
mangleCXXCtorType(Ctor_Complete);
break;
case DeclarationName::CXXDestructorName:
Anders Carlsson
committed
if (ND == Structor)
// If the named decl is the C++ destructor we're mangling, use the type we
// were given.
Anders Carlsson
committed
mangleCXXDtorType(static_cast<CXXDtorType>(StructorType));
else
// Otherwise, use the complete destructor name. This is relevant if a
// class with a destructor is declared within a destructor.
mangleCXXDtorType(Dtor_Complete);
break;
case DeclarationName::CXXConversionFunctionName:
// <operator-name> ::= cv <type> # (cast)
Out << "cv";
Anders Carlsson
committed
mangleType(Context.getASTContext().getCanonicalType(Name.getCXXNameType()));
break;
case DeclarationName::CXXOperatorName:
mangleOperatorName(Name.getCXXOverloadedOperator(),
cast<FunctionDecl>(ND)->getNumParams());
break;
case DeclarationName::CXXUsingDirective:
assert(false && "Can't mangle a using directive name!");
}
}
void CXXNameMangler::mangleSourceName(const IdentifierInfo *II) {
// <source-name> ::= <positive length number> <identifier>
// <number> ::= [n] <non-negative decimal integer>
// <identifier> ::= <unqualified source code identifier>
Out << II->getLength() << II->getName();
}
void CXXNameMangler::mangleNestedName(const NamedDecl *ND) {
// <nested-name> ::= N [<CV-qualifiers>] <prefix> <unqualified-name> E
// ::= N [<CV-qualifiers>] <template-prefix> <template-args> E
Out << 'N';
if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(ND))
mangleQualifiers(Qualifiers::fromCVRMask(Method->getTypeQualifiers()));
// Check if we have a template.
const TemplateArgumentList *TemplateArgs = 0;
Anders Carlsson
committed
if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) {
mangleTemplatePrefix(TD);
mangleTemplateArgumentList(*TemplateArgs);
} else {
manglePrefix(ND->getDeclContext());
mangleUnqualifiedName(ND);
}
Out << 'E';
}
void CXXNameMangler::mangleNestedName(const TemplateDecl *TD,
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs) {
Anders Carlsson
committed
// <nested-name> ::= N [<CV-qualifiers>] <template-prefix> <template-args> E
Anders Carlsson
committed
mangleTemplatePrefix(TD);
mangleTemplateArgs(TemplateArgs, NumTemplateArgs);
Anders Carlsson
committed
void CXXNameMangler::mangleLocalName(const NamedDecl *ND) {
// <local-name> := Z <function encoding> E <entity name> [<discriminator>]
// := Z <function encoding> E s [<discriminator>]
// <discriminator> := _ <non-negative number>
Out << 'Z';
mangleFunctionEncoding(cast<FunctionDecl>(ND->getDeclContext()));
Out << 'E';
mangleSourceName(ND->getIdentifier());
}
void CXXNameMangler::manglePrefix(const DeclContext *DC) {
// <prefix> ::= <prefix> <unqualified-name>
// ::= <template-prefix> <template-args>
// ::= <template-param>
// ::= # empty
// ::= <substitution>
// FIXME: We only handle mangling of namespaces and classes at the moment.
Anders Carlsson
committed
while (isa<LinkageSpecDecl>(DC))
DC = DC->getParent();
if (DC->isTranslationUnit())
return;
if (mangleSubstitution(cast<NamedDecl>(DC)))
return;
// Check if we have a template.
const TemplateArgumentList *TemplateArgs = 0;
Anders Carlsson
committed
if (const TemplateDecl *TD = isTemplate(cast<NamedDecl>(DC), TemplateArgs)) {
mangleTemplatePrefix(TD);
mangleTemplateArgumentList(*TemplateArgs);
} else {
manglePrefix(DC->getParent());
mangleUnqualifiedName(cast<NamedDecl>(DC));
}
}
Anders Carlsson
committed
void CXXNameMangler::mangleTemplatePrefix(const TemplateDecl *ND) {
// <template-prefix> ::= <prefix> <template unqualified-name>
// ::= <template-param>
// ::= <substitution>
if (mangleSubstitution(ND))
return;
// FIXME: <template-param>
mangleUnqualifiedName(ND->getTemplatedDecl());
addSubstitution(ND);
CXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity) {
switch (OO) {
Sebastian Redl
committed
// <operator-name> ::= nw # new
case OO_New: Out << "nw"; break;
// ::= na # new[]
case OO_Array_New: Out << "na"; break;
Sebastian Redl
committed
// ::= dl # delete
case OO_Delete: Out << "dl"; break;
Sebastian Redl
committed
// ::= da # delete[]
case OO_Array_Delete: Out << "da"; break;
// ::= ps # + (unary)
// ::= pl # +
case OO_Plus: Out << (Arity == 1? "ps" : "pl"); break;
Sebastian Redl
committed
// ::= ng # - (unary)
// ::= mi # -
case OO_Minus: Out << (Arity == 1? "ng" : "mi"); break;
Sebastian Redl
committed
// ::= ad # & (unary)
// ::= an # &
case OO_Amp: Out << (Arity == 1? "ad" : "an"); break;
Sebastian Redl
committed
// ::= de # * (unary)
// ::= ml # *
case OO_Star: Out << (Arity == 1? "de" : "ml"); break;
Sebastian Redl
committed
// ::= co # ~
case OO_Tilde: Out << "co"; break;
Sebastian Redl
committed
// ::= dv # /
case OO_Slash: Out << "dv"; break;
Sebastian Redl
committed
// ::= rm # %
case OO_Percent: Out << "rm"; break;
Sebastian Redl
committed
// ::= or # |
case OO_Pipe: Out << "or"; break;
// ::= eo # ^
case OO_Caret: Out << "eo"; break;
Sebastian Redl
committed
// ::= aS # =
case OO_Equal: Out << "aS"; break;
Sebastian Redl
committed
// ::= pL # +=
case OO_PlusEqual: Out << "pL"; break;
Sebastian Redl
committed
// ::= mI # -=
case OO_MinusEqual: Out << "mI"; break;
Sebastian Redl
committed
// ::= mL # *=
case OO_StarEqual: Out << "mL"; break;
Sebastian Redl
committed
// ::= dV # /=
case OO_SlashEqual: Out << "dV"; break;
Sebastian Redl
committed
// ::= rM # %=
case OO_PercentEqual: Out << "rM"; break;
// ::= aN # &=
case OO_AmpEqual: Out << "aN"; break;
// ::= oR # |=
case OO_PipeEqual: Out << "oR"; break;
// ::= eO # ^=
case OO_CaretEqual: Out << "eO"; break;
// ::= ls # <<
case OO_LessLess: Out << "ls"; break;
Sebastian Redl
committed
// ::= rs # >>
case OO_GreaterGreater: Out << "rs"; break;
// ::= lS # <<=
case OO_LessLessEqual: Out << "lS"; break;
// ::= rS # >>=
case OO_GreaterGreaterEqual: Out << "rS"; break;
// ::= eq # ==
case OO_EqualEqual: Out << "eq"; break;
Sebastian Redl
committed
// ::= ne # !=
case OO_ExclaimEqual: Out << "ne"; break;
// ::= lt # <
case OO_Less: Out << "lt"; break;
Sebastian Redl
committed
// ::= gt # >
case OO_Greater: Out << "gt"; break;
Sebastian Redl
committed
// ::= le # <=
case OO_LessEqual: Out << "le"; break;
Sebastian Redl
committed
// ::= ge # >=
case OO_GreaterEqual: Out << "ge"; break;
Sebastian Redl
committed
// ::= nt # !
case OO_Exclaim: Out << "nt"; break;
Sebastian Redl
committed
// ::= aa # &&
case OO_AmpAmp: Out << "aa"; break;
Sebastian Redl
committed
// ::= oo # ||
case OO_PipePipe: Out << "oo"; break;
// ::= pp # ++
case OO_PlusPlus: Out << "pp"; break;
// ::= mm # --
case OO_MinusMinus: Out << "mm"; break;
Sebastian Redl
committed
// ::= cm # ,
case OO_Comma: Out << "cm"; break;
// ::= pm # ->*
case OO_ArrowStar: Out << "pm"; break;
Sebastian Redl
committed
// ::= pt # ->
case OO_Arrow: Out << "pt"; break;
Sebastian Redl
committed
// ::= cl # ()
case OO_Call: Out << "cl"; break;
Sebastian Redl
committed
// ::= ix # []
case OO_Subscript: Out << "ix"; break;
// UNSUPPORTED: ::= qu # ?
Sebastian Redl
committed
case OO_None:
case OO_Conditional:
case NUM_OVERLOADED_OPERATORS:
assert(false && "Not an overloaded operator");
break;
}
}
void CXXNameMangler::mangleQualifiers(Qualifiers Quals) {
// <CV-qualifiers> ::= [r] [V] [K] # restrict (C99), volatile, const
if (Quals.hasRestrict())
Out << 'r';
if (Quals.hasVolatile())
Out << 'V';
if (Quals.hasConst())
Out << 'K';
// FIXME: For now, just drop all extension qualifiers on the floor.
}
void CXXNameMangler::mangleType(QualType T) {
// Only operate on the canonical type!
Anders Carlsson
committed
T = Context.getASTContext().getCanonicalType(T);
bool IsSubstitutable = T.hasQualifiers() || !isa<BuiltinType>(T);
Anders Carlsson
committed
if (IsSubstitutable && mangleSubstitution(T))
return;
if (Qualifiers Quals = T.getQualifiers()) {
mangleQualifiers(Quals);
// Recurse: even if the qualified type isn't yet substitutable,
// the unqualified type might be.
Anders Carlsson
committed
mangleType(T.getUnqualifiedType());
} else {
switch (T->getTypeClass()) {
John McCall
committed
#define ABSTRACT_TYPE(CLASS, PARENT)
#define NON_CANONICAL_TYPE(CLASS, PARENT) \
Anders Carlsson
committed
case Type::CLASS: \
llvm::llvm_unreachable("can't mangle non-canonical type " #CLASS "Type"); \
return;
John McCall
committed
#define TYPE(CLASS, PARENT) \
Anders Carlsson
committed
case Type::CLASS: \
mangleType(static_cast<const CLASS##Type*>(T.getTypePtr())); \
Anders Carlsson
committed
break;
John McCall
committed
#include "clang/AST/TypeNodes.def"
Anders Carlsson
committed
}
Anders Carlsson
committed
// Add the substitution.
if (IsSubstitutable)
addSubstitution(T);
}
void CXXNameMangler::mangleType(const BuiltinType *T) {
John McCall
committed
// <type> ::= <builtin-type>
// <builtin-type> ::= v # void
// ::= w # wchar_t
// ::= b # bool
// ::= c # char
// ::= a # signed char
// ::= h # unsigned char
// ::= s # short
// ::= t # unsigned short
// ::= i # int
// ::= j # unsigned int
// ::= l # long
// ::= m # unsigned long
// ::= x # long long, __int64
// ::= y # unsigned long long, __int64
// ::= n # __int128
// UNSUPPORTED: ::= o # unsigned __int128
// ::= f # float
// ::= d # double
// ::= e # long double, __float80
// UNSUPPORTED: ::= g # __float128
// UNSUPPORTED: ::= Dd # IEEE 754r decimal floating point (64 bits)
// UNSUPPORTED: ::= De # IEEE 754r decimal floating point (128 bits)
// UNSUPPORTED: ::= Df # IEEE 754r decimal floating point (32 bits)
// UNSUPPORTED: ::= Dh # IEEE 754r half-precision floating point (16 bits)
Alisdair Meredith
committed
// ::= Di # char32_t
// ::= Ds # char16_t
// ::= u <source-name> # vendor extended type
// From our point of view, std::nullptr_t is a builtin, but as far as mangling
// is concerned, it's a type called std::nullptr_t.
switch (T->getKind()) {
case BuiltinType::Void: Out << 'v'; break;
case BuiltinType::Bool: Out << 'b'; break;
case BuiltinType::Char_U: case BuiltinType::Char_S: Out << 'c'; break;
case BuiltinType::UChar: Out << 'h'; break;
case BuiltinType::UShort: Out << 't'; break;
case BuiltinType::UInt: Out << 'j'; break;
case BuiltinType::ULong: Out << 'm'; break;
case BuiltinType::ULongLong: Out << 'y'; break;
case BuiltinType::UInt128: Out << 'o'; break;
case BuiltinType::SChar: Out << 'a'; break;
case BuiltinType::WChar: Out << 'w'; break;
Alisdair Meredith
committed
case BuiltinType::Char16: Out << "Ds"; break;
case BuiltinType::Char32: Out << "Di"; break;
case BuiltinType::Short: Out << 's'; break;
case BuiltinType::Int: Out << 'i'; break;
case BuiltinType::Long: Out << 'l'; break;
case BuiltinType::LongLong: Out << 'x'; break;
case BuiltinType::Int128: Out << 'n'; break;
case BuiltinType::Float: Out << 'f'; break;
case BuiltinType::Double: Out << 'd'; break;
case BuiltinType::LongDouble: Out << 'e'; break;
case BuiltinType::NullPtr: Out << "St9nullptr_t"; break;
case BuiltinType::Overload:
case BuiltinType::Dependent:
"Overloaded and dependent types shouldn't get to name mangling");
break;
case BuiltinType::UndeducedAuto:
assert(0 && "Should not see undeduced auto here");
break;
Steve Naroff
committed
case BuiltinType::ObjCId: Out << "11objc_object"; break;
case BuiltinType::ObjCClass: Out << "10objc_class"; break;
}
}
John McCall
committed
// <type> ::= <function-type>
// <function-type> ::= F [Y] <bare-function-type> E
void CXXNameMangler::mangleType(const FunctionProtoType *T) {
Out << 'F';
// FIXME: We don't have enough information in the AST to produce the 'Y'
// encoding for extern "C" function types.
mangleBareFunctionType(T, /*MangleReturnType=*/true);
Out << 'E';
}
John McCall
committed
void CXXNameMangler::mangleType(const FunctionNoProtoType *T) {
llvm::llvm_unreachable("Can't mangle K&R function prototypes");
}
void CXXNameMangler::mangleBareFunctionType(const FunctionType *T,
bool MangleReturnType) {
John McCall
committed
// We should never be mangling something without a prototype.
const FunctionProtoType *Proto = cast<FunctionProtoType>(T);
// <bare-function-type> ::= <signature type>+
if (MangleReturnType)
John McCall
committed
mangleType(Proto->getResultType());
Anders Carlsson
committed
if (Proto->getNumArgs() == 0) {
Out << 'v';
return;
}
for (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(),
Arg != ArgEnd; ++Arg)
mangleType(*Arg);
// <builtin-type> ::= z # ellipsis
if (Proto->isVariadic())
Out << 'z';
}
John McCall
committed
// <type> ::= <class-enum-type>
John McCall
committed
void CXXNameMangler::mangleType(const EnumType *T) {
mangleType(static_cast<const TagType*>(T));
}
void CXXNameMangler::mangleType(const RecordType *T) {
mangleType(static_cast<const TagType*>(T));
}
void CXXNameMangler::mangleType(const TagType *T) {
if (!T->getDecl()->getIdentifier())
mangleName(T->getDecl()->getTypedefForAnonDecl());
else
mangleName(T->getDecl());
}
John McCall
committed
// <type> ::= <array-type>
// <array-type> ::= A <positive dimension number> _ <element type>
// ::= A [<dimension expression>] _ <element type>
void CXXNameMangler::mangleType(const ConstantArrayType *T) {
Out << 'A' << T->getSize() << '_';
mangleType(T->getElementType());
}
void CXXNameMangler::mangleType(const VariableArrayType *T) {
Out << 'A';
John McCall
committed
mangleExpression(T->getSizeExpr());
Out << '_';
mangleType(T->getElementType());
}
John McCall
committed
void CXXNameMangler::mangleType(const DependentSizedArrayType *T) {
Out << 'A';
mangleExpression(T->getSizeExpr());
Out << '_';
mangleType(T->getElementType());
}
void CXXNameMangler::mangleType(const IncompleteArrayType *T) {
Out << 'A' << '_';
mangleType(T->getElementType());
}
John McCall
committed
// <type> ::= <pointer-to-member-type>
// <pointer-to-member-type> ::= M <class type> <member type>
void CXXNameMangler::mangleType(const MemberPointerType *T) {
Out << 'M';
mangleType(QualType(T->getClass(), 0));
Anders Carlsson
committed
QualType PointeeType = T->getPointeeType();
if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(PointeeType)) {
mangleQualifiers(Qualifiers::fromCVRMask(FPT->getTypeQuals()));
Anders Carlsson
committed
mangleType(FPT);
Anders Carlsson
committed
mangleType(PointeeType);
}
John McCall
committed
// <type> ::= <template-param>
void CXXNameMangler::mangleType(const TemplateTypeParmType *T) {
mangleTemplateParameter(T->getIndex());
}
John McCall
committed
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
// FIXME: <type> ::= <template-template-param> <template-args>
// <type> ::= P <type> # pointer-to
void CXXNameMangler::mangleType(const PointerType *T) {
Out << 'P';
mangleType(T->getPointeeType());
}
void CXXNameMangler::mangleType(const ObjCObjectPointerType *T) {
Out << 'P';
mangleType(T->getPointeeType());
}
// <type> ::= R <type> # reference-to
void CXXNameMangler::mangleType(const LValueReferenceType *T) {
Out << 'R';
mangleType(T->getPointeeType());
}
// <type> ::= O <type> # rvalue reference-to (C++0x)
void CXXNameMangler::mangleType(const RValueReferenceType *T) {
Out << 'O';
mangleType(T->getPointeeType());
}
// <type> ::= C <type> # complex pair (C 2000)
void CXXNameMangler::mangleType(const ComplexType *T) {
Out << 'C';
mangleType(T->getElementType());
}
// GNU extension: vector types
void CXXNameMangler::mangleType(const VectorType *T) {
Out << "U8__vector";
mangleType(T->getElementType());
}
void CXXNameMangler::mangleType(const ExtVectorType *T) {
mangleType(static_cast<const VectorType*>(T));
}
void CXXNameMangler::mangleType(const DependentSizedExtVectorType *T) {
Out << "U8__vector";
mangleType(T->getElementType());
}
Anders Carlsson
committed
void CXXNameMangler::mangleType(const ObjCInterfaceType *T) {
mangleSourceName(T->getDecl()->getIdentifier());
}
John McCall
committed
void CXXNameMangler::mangleType(const BlockPointerType *T) {
assert(false && "can't mangle block pointer types yet");
}
void CXXNameMangler::mangleType(const FixedWidthIntType *T) {
assert(false && "can't mangle arbitary-precision integer type yet");
}
void CXXNameMangler::mangleType(const TemplateSpecializationType *T) {
TemplateDecl *TD = T->getTemplateName().getAsTemplateDecl();
assert(TD && "FIXME: Support dependent template names!");
mangleName(TD, T->getArgs(), T->getNumArgs());
John McCall
committed
}
void CXXNameMangler::mangleType(const TypenameType *T) {
// Typename types are always nested
Out << 'N';
const Type *QTy = T->getQualifier()->getAsType();
if (const TemplateSpecializationType *TST =
dyn_cast<TemplateSpecializationType>(QTy)) {
if (!mangleSubstitution(QualType(TST, 0))) {
TemplateDecl *TD = TST->getTemplateName().getAsTemplateDecl();