diff options
Diffstat (limited to 'lib/CodeGen/Mangle.cpp')
-rw-r--r-- | lib/CodeGen/Mangle.cpp | 516 |
1 files changed, 516 insertions, 0 deletions
diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp new file mode 100644 index 0000000000..a97ac58dd7 --- /dev/null +++ b/lib/CodeGen/Mangle.cpp @@ -0,0 +1,516 @@ +//===--------------------- Mangle.cpp - Mangle C++ Names ------------------===// +// +// 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" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/raw_ostream.h" +using namespace clang; + +namespace { + class VISIBILITY_HIDDEN CXXNameMangler { + ASTContext &Context; + llvm::raw_ostream &Out; + + public: + CXXNameMangler(ASTContext &C, llvm::raw_ostream &os) + : Context(C), Out(os) { } + + bool mangle(const NamedDecl *D); + void mangleFunctionEncoding(const FunctionDecl *FD); + void mangleName(const NamedDecl *ND); + void mangleUnqualifiedName(const NamedDecl *ND); + void mangleSourceName(const IdentifierInfo *II); + void mangleNestedName(const NamedDecl *ND); + void manglePrefix(const DeclContext *DC); + void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity); + void mangleCVQualifiers(unsigned Quals); + void mangleType(QualType T); + void mangleType(const BuiltinType *T); + void mangleType(const FunctionType *T); + void mangleBareFunctionType(const FunctionType *T, bool MangleReturnType); + void mangleType(const TagType *T); + void mangleType(const ArrayType *T); + void mangleType(const MemberPointerType *T); + void mangleType(const TemplateTypeParmType *T); + void mangleExpression(Expr *E); + }; +} + + +bool CXXNameMangler::mangle(const NamedDecl *D) { + // <mangled-name> ::= _Z <encoding> + // ::= <data name> + // ::= <special-name> + + // FIXME: Actually use a visitor to decode these? + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + bool RequiresMangling = false; + // Clang's "overloadable" attribute extension to C/C++ + if (FD->getAttr<OverloadableAttr>()) + RequiresMangling = true; + else if (Context.getLangOptions().CPlusPlus) { + RequiresMangling = true; + if (isa<LinkageSpecDecl>(FD->getDeclContext()) && + cast<LinkageSpecDecl>(FD->getDeclContext())->getLanguage() + == LinkageSpecDecl::lang_c) { + // Entities with C linkage are not mangled. + RequiresMangling = false; + } + } + + if (RequiresMangling) { + Out << "_Z"; + mangleFunctionEncoding(FD); + return true; + } + } + + return false; +} + +void CXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) { + // <encoding> ::= <function name> <bare-function-type> + mangleName(FD); + mangleBareFunctionType(FD->getType()->getAsFunctionType(), false); +} + +static bool isStdNamespace(const DeclContext *DC) { + if (!DC->isNamespace() || !DC->getParent()->isTranslationUnit()) + return false; + + const NamespaceDecl *NS = cast<NamespaceDecl>(DC); + const IdentifierInfo *Name = NS->getIdentifier(); + if (Name->getLength() != 3) + return false; + + const char *Str = Name->getName(); + if (Str[0] != 's' || Str[1] != 't' || Str[2] != 'd') + return false; + + return true; +} + +void CXXNameMangler::mangleName(const NamedDecl *ND) { + // <name> ::= <nested-name> + // ::= <unscoped-name> + // ::= <unscoped-template-name> <template-args> + // ::= <local-name> # See Scope Encoding below + // + // <unscoped-name> ::= <unqualified-name> + // ::= St <unqualified-name> # ::std:: + if (ND->getDeclContext()->isTranslationUnit()) + mangleUnqualifiedName(ND); + else if (isStdNamespace(ND->getDeclContext())) { + Out << "St"; + mangleUnqualifiedName(ND); + } else { + mangleNestedName(ND); + } +} + +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: + mangleSourceName(Name.getAsIdentifierInfo()); + break; + + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + assert(false && "Can't mangle Objective-C selector names here!"); + break; + + case DeclarationName::CXXConstructorName: + // <ctor-dtor-name> ::= C1 # complete object constructor + // ::= C2 # base object constructor + // ::= C3 # complete object allocating constructor + // + // FIXME: We don't even have all of these constructors + // in the AST yet. + Out << "C1"; + break; + + case DeclarationName::CXXDestructorName: + // <ctor-dtor-name> ::= D0 # deleting destructor + // ::= D1 # complete object destructor + // ::= D2 # base object destructor + // + // FIXME: We don't even have all of these destructors in the AST + // yet. + Out << "D0"; + break; + + case DeclarationName::CXXConversionFunctionName: + assert(false && "Not sure how to mangle conversion functions yet"); + 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 + // FIXME: no template support + Out << 'N'; + if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(ND)) + mangleCVQualifiers(Method->getTypeQualifiers()); + manglePrefix(ND->getDeclContext()); + mangleUnqualifiedName(ND); + Out << 'E'; +} + +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. + if (DC->getParent() != DC) + manglePrefix(DC); + + if (const NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(DC)) + mangleSourceName(Namespace->getIdentifier()); + else if (const RecordDecl *Record = dyn_cast<RecordDecl>(DC)) + mangleSourceName(Record->getIdentifier()); +} + +void +CXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity) { + switch (OO) { + // <operator-name> ::= nw # new + case OO_New: Out << "nw"; break; + // ::= na # new[] + case OO_Array_New: Out << "na"; break; + // ::= dl # delete + case OO_Delete: Out << "dl"; break; + // ::= da # delete[] + case OO_Array_Delete: Out << "da"; break; + // ::= ps # + (unary) + // ::= pl # + + case OO_Plus: Out << (Arity == 1? "ps" : "pl"); break; + // ::= ng # - (unary) + // ::= mi # - + case OO_Minus: Out << (Arity == 1? "ng" : "mi"); break; + // ::= ad # & (unary) + // ::= an # & + case OO_Amp: Out << (Arity == 1? "ad" : "an"); break; + // ::= de # * (unary) + // ::= ml # * + case OO_Star: Out << (Arity == 1? "de" : "ml"); break; + // ::= co # ~ + case OO_Tilde: Out << "co"; break; + // ::= dv # / + case OO_Slash: Out << "dv"; break; + // ::= rm # % + case OO_Percent: Out << "rm"; break; + // ::= or # | + case OO_Pipe: Out << "or"; break; + // ::= eo # ^ + case OO_Caret: Out << "eo"; break; + // ::= aS # = + case OO_Equal: Out << "aS"; break; + // ::= pL # += + case OO_PlusEqual: Out << "pL"; break; + // ::= mI # -= + case OO_MinusEqual: Out << "mI"; break; + // ::= mL # *= + case OO_StarEqual: Out << "mL"; break; + // ::= dV # /= + case OO_SlashEqual: Out << "dV"; break; + // ::= 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; + // ::= 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; + // ::= ne # != + case OO_ExclaimEqual: Out << "ne"; break; + // ::= lt # < + case OO_Less: Out << "lt"; break; + // ::= gt # > + case OO_Greater: Out << "gt"; break; + // ::= le # <= + case OO_LessEqual: Out << "le"; break; + // ::= ge # >= + case OO_GreaterEqual: Out << "ge"; break; + // ::= nt # ! + case OO_Exclaim: Out << "nt"; break; + // ::= aa # && + case OO_AmpAmp: Out << "aa"; break; + // ::= oo # || + case OO_PipePipe: Out << "oo"; break; + // ::= pp # ++ + case OO_PlusPlus: Out << "pp"; break; + // ::= mm # -- + case OO_MinusMinus: Out << "mm"; break; + // ::= cm # , + case OO_Comma: Out << "cm"; break; + // ::= pm # ->* + case OO_ArrowStar: Out << "pm"; break; + // ::= pt # -> + case OO_Arrow: Out << "pt"; break; + // ::= cl # () + case OO_Call: Out << "cl"; break; + // ::= ix # [] + case OO_Subscript: Out << "ix"; break; + // UNSUPPORTED: ::= qu # ? + + case OO_None: + case NUM_OVERLOADED_OPERATORS: + assert(false && "Not an ovelroaded operator"); + break; + } +} + +void CXXNameMangler::mangleCVQualifiers(unsigned Quals) { + // <CV-qualifiers> ::= [r] [V] [K] # restrict (C99), volatile, const + if (Quals & QualType::Restrict) + Out << 'r'; + if (Quals & QualType::Volatile) + Out << 'V'; + if (Quals & QualType::Const) + Out << 'K'; +} + +void CXXNameMangler::mangleType(QualType T) { + // Only operate on the canonical type! + T = Context.getCanonicalType(T); + + // FIXME: Should we have a TypeNodes.def to make this easier? (YES!) + + // <type> ::= <CV-qualifiers> <type> + mangleCVQualifiers(T.getCVRQualifiers()); + + // ::= <builtin-type> + if (const BuiltinType *BT = dyn_cast<BuiltinType>(T.getTypePtr())) + mangleType(BT); + // ::= <function-type> + else if (const FunctionType *FT = dyn_cast<FunctionType>(T.getTypePtr())) + mangleType(FT); + // ::= <class-enum-type> + else if (const TagType *TT = dyn_cast<TagType>(T.getTypePtr())) + mangleType(TT); + // ::= <array-type> + else if (const ArrayType *AT = dyn_cast<ArrayType>(T.getTypePtr())) + mangleType(AT); + // ::= <pointer-to-member-type> + else if (const MemberPointerType *MPT + = dyn_cast<MemberPointerType>(T.getTypePtr())) + mangleType(MPT); + // ::= <template-param> + else if (const TemplateTypeParmType *TypeParm + = dyn_cast<TemplateTypeParmType>(T.getTypePtr())) + mangleType(TypeParm); + // FIXME: ::= <template-template-param> <template-args> + // FIXME: ::= <substitution> # See Compression below + // ::= P <type> # pointer-to + else if (const PointerType *PT = dyn_cast<PointerType>(T.getTypePtr())) { + Out << 'P'; + mangleType(PT->getPointeeType()); + } + // ::= R <type> # reference-to + // ::= O <type> # rvalue reference-to (C++0x) + else if (const ReferenceType *RT = dyn_cast<ReferenceType>(T.getTypePtr())) { + // FIXME: rvalue references + Out << 'R'; + mangleType(RT->getPointeeType()); + } + // ::= C <type> # complex pair (C 2000) + else if (const ComplexType *CT = dyn_cast<ComplexType>(T.getTypePtr())) { + Out << 'C'; + mangleType(CT->getElementType()); + } else if (const VectorType *VT = dyn_cast<VectorType>(T.getTypePtr())) { + // GNU extension: vector types + Out << "U8__vector"; + mangleType(VT->getElementType()); + } + // FIXME: ::= G <type> # imaginary (C 2000) + // FIXME: ::= U <source-name> <type> # vendor extended type qualifier + else + assert(false && "Cannot mangle unknown type"); +} + +void CXXNameMangler::mangleType(const BuiltinType *T) { + // <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 + // NOT HERE: ::= z # ellipsis + // 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) + // UNSUPPORTED: ::= Di # char32_t + // UNSUPPORTED: ::= Ds # char16_t + // ::= u <source-name> # vendor extended type + 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::SChar: Out << 'a'; break; + case BuiltinType::WChar: Out << 'w'; 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::Float: Out << 'f'; break; + case BuiltinType::Double: Out << 'd'; break; + case BuiltinType::LongDouble: Out << 'e'; break; + + case BuiltinType::Overload: + case BuiltinType::Dependent: + assert(false && + "Overloaded and dependent types shouldn't get to name mangling"); + break; + } +} + +void CXXNameMangler::mangleType(const FunctionType *T) { + // <function-type> ::= F [Y] <bare-function-type> E + 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'; +} + +void CXXNameMangler::mangleBareFunctionType(const FunctionType *T, + bool MangleReturnType) { + // <bare-function-type> ::= <signature type>+ + if (MangleReturnType) + mangleType(T->getResultType()); + + const FunctionTypeProto *Proto = dyn_cast<FunctionTypeProto>(T); + assert(Proto && "Can't mangle K&R function prototypes"); + + for (FunctionTypeProto::arg_type_iterator Arg = Proto->arg_type_begin(), + ArgEnd = Proto->arg_type_end(); + Arg != ArgEnd; ++Arg) + mangleType(*Arg); +} + +void CXXNameMangler::mangleType(const TagType *T) { + // <class-enum-type> ::= <name> + mangleName(T->getDecl()); +} + +void CXXNameMangler::mangleType(const ArrayType *T) { + // <array-type> ::= A <positive dimension number> _ <element type> + // ::= A [<dimension expression>] _ <element type> + Out << 'A'; + if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(T)) + Out << CAT->getSize(); + else if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(T)) + mangleExpression(VAT->getSizeExpr()); + else if (const DependentSizedArrayType *DSAT + = dyn_cast<DependentSizedArrayType>(T)) + mangleExpression(DSAT->getSizeExpr()); + + Out << '_'; + mangleType(T->getElementType()); +} + +void CXXNameMangler::mangleType(const MemberPointerType *T) { + // <pointer-to-member-type> ::= M <class type> <member type> + Out << 'M'; + mangleType(QualType(T->getClass(), 0)); + mangleType(T->getPointeeType()); +} + +void CXXNameMangler::mangleType(const TemplateTypeParmType *T) { + // <template-param> ::= T_ # first template parameter + // ::= T <parameter-2 non-negative number> _ + if (T->getIndex() == 0) + Out << "T_"; + else + Out << 'T' << (T->getIndex() - 1) << '_'; +} + +void CXXNameMangler::mangleExpression(Expr *E) { + assert(false && "Cannot mangle expressions yet"); +} + +namespace clang { + /// \brief Mangles the name of the declaration D and emits that name + /// to the given output stream. + /// + /// If the declaration D requires a mangled name, this routine will + /// emit that mangled name to \p os and return true. Otherwise, \p + /// os will be unchanged and this routine will return false. In this + /// case, the caller should just emit the identifier of the declaration + /// (\c D->getIdentifier()) as its name. + bool mangleName(const NamedDecl *D, ASTContext &Context, + llvm::raw_ostream &os) { + CXXNameMangler Mangler(Context, os); + return Mangler.mangle(D); + } +} + |