From: Charles Davis Date: Wed, 16 Jun 2010 05:33:16 +0000 (+0000) Subject: Start mangling function types in the Microsoft C++ Mangler. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=65161d17cbf8980e24643c65b74a5127dcb7ac22;p=clang Start mangling function types in the Microsoft C++ Mangler. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@106081 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp index e8016a93e3..4d26a58d90 100644 --- a/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/lib/CodeGen/MicrosoftCXXABI.cpp @@ -45,6 +45,7 @@ public: void mangle(const NamedDecl *D, llvm::StringRef Prefix = "?"); void mangleName(const NamedDecl *ND); + void mangleFunctionEncoding(const FunctionDecl *FD); void mangleVariableEncoding(const VarDecl *VD); void mangleType(QualType T); @@ -65,6 +66,11 @@ private: #define TYPE(CLASS, PARENT) void mangleType(const CLASS##Type *T); #include "clang/AST/TypeNodes.def" + void mangleType(const FunctionType *T, bool IsStructor); + void mangleFunctionClass(const FunctionDecl *FD); + void mangleCallingConvention(const FunctionType *T); + void mangleThrowSpecification(const FunctionProtoType *T); + }; /// MicrosoftMangleContext - Overrides the default MangleContext for the @@ -174,16 +180,64 @@ void MicrosoftCXXNameMangler::mangle(const NamedDecl *D, return; } - // ::= ? + // ::= ? Out << Prefix; mangleName(D); - if (const VarDecl *VD = dyn_cast(D)) + if (const FunctionDecl *FD = dyn_cast(D)) + mangleFunctionEncoding(FD); + else if (const VarDecl *VD = dyn_cast(D)) mangleVariableEncoding(VD); - // TODO: Function types. + // TODO: Fields? Can MSVC even mangle them? +} + +void MicrosoftCXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) { + // ::= + + // Don't mangle in the type if this isn't a decl we should typically mangle. + if (!Context.shouldMangleDeclName(FD)) + return; + + // We should never ever see a FunctionNoProtoType at this point. + // We don't even know how to mangle their types anyway :). + FunctionProtoType *OldType = cast(FD->getType()); + + bool InStructor = false; + const CXXMethodDecl *MD = dyn_cast(FD); + if (MD) { + if (isa(MD) || isa(MD)) + InStructor = true; + } + + // First, the function class. + mangleFunctionClass(FD); + + // If this is a C++ instance method, mangle the CVR qualifiers for the + // this pointer. + if (MD && MD->isInstance()) + mangleQualifiers(Qualifiers::fromCVRMask(OldType->getTypeQuals()), false); + + // Do the canonicalization out here because parameter types can + // undergo additional canonicalization (e.g. array decay). + const FunctionProtoType *FT = cast(getASTContext() + .getCanonicalType(OldType)); + // If the function's type had a throw spec, canonicalization removed it. + // Get it back. + FT = cast(getASTContext().getFunctionType( + FT->getResultType(), + FT->arg_type_begin(), + FT->getNumArgs(), + FT->isVariadic(), + FT->getTypeQuals(), + OldType->hasExceptionSpec(), + OldType->hasAnyExceptionSpec(), + OldType->getNumExceptions(), + OldType->exception_begin(), + FT->getExtInfo()).getTypePtr()); + mangleType(FT, InStructor); } void MicrosoftCXXNameMangler::mangleVariableEncoding(const VarDecl *VD) { - // ::= + // ::= // ::= 0 # private static member // ::= 1 # protected static member // ::= 2 # public static member @@ -523,6 +577,149 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T) { } } +// ::= +void MicrosoftCXXNameMangler::mangleType(const FunctionProtoType *T) { + // Structors only appear in decls, so at this point we know it's not a + // structor type. + mangleType(T, false); +} +void MicrosoftCXXNameMangler::mangleType(const FunctionNoProtoType *T) { + llvm_unreachable("Can't mangle K&R function prototypes"); +} + +void MicrosoftCXXNameMangler::mangleType(const FunctionType *T, + bool IsStructor) { + // ::= + // + mangleCallingConvention(T); + + const FunctionProtoType *Proto = cast(T); + + // Structors always have a 'void' return type, but MSVC mangles them as an + // '@' (because they have no declared return type). + if (IsStructor) + Out << '@'; + else + mangleType(Proto->getResultType()); + + // ::= X # void + // ::= + @ + // ::= * Z # varargs + if (Proto->getNumArgs() == 0 && !Proto->isVariadic()) { + Out << 'X'; + } else { + for (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(), + ArgEnd = Proto->arg_type_end(); + Arg != ArgEnd; ++Arg) + mangleType(*Arg); + + // ::= Z # ellipsis + if (Proto->isVariadic()) + Out << 'Z'; + else + Out << '@'; + } + + mangleThrowSpecification(Proto); +} + +void MicrosoftCXXNameMangler::mangleFunctionClass(const FunctionDecl *FD) { + // ::= A # private: near + // ::= B # private: far + // ::= C # private: static near + // ::= D # private: static far + // ::= E # private: virtual near + // ::= F # private: virtual far + // ::= G # private: thunk near + // ::= H # private: thunk far + // ::= I # protected: near + // ::= J # protected: far + // ::= K # protected: static near + // ::= L # protected: static far + // ::= M # protected: virtual near + // ::= N # protected: virtual far + // ::= O # protected: thunk near + // ::= P # protected: thunk far + // ::= Q # public: near + // ::= R # public: far + // ::= S # public: static near + // ::= T # public: static far + // ::= U # public: virtual near + // ::= V # public: virtual far + // ::= W # public: thunk near + // ::= X # public: thunk far + // ::= Y # global near + // ::= Z # global far + if (const CXXMethodDecl *MD = dyn_cast(FD)) { + switch (MD->getAccess()) { + default: + case AS_private: + if (MD->isStatic()) + Out << 'C'; + else if (MD->isVirtual()) + Out << 'E'; + else + Out << 'A'; + break; + case AS_protected: + if (MD->isStatic()) + Out << 'K'; + else if (MD->isVirtual()) + Out << 'M'; + else + Out << 'I'; + break; + case AS_public: + if (MD->isStatic()) + Out << 'S'; + else if (MD->isVirtual()) + Out << 'U'; + else + Out << 'Q'; + } + } else + Out << 'Y'; +} +void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T) { + // ::= A # __cdecl + // ::= B # __export __cdecl + // ::= C # __pascal + // ::= D # __export __pascal + // ::= E # __thiscall + // ::= F # __export __thiscall + // ::= G # __stdcall + // ::= H # __export __stdcall + // ::= I # __fastcall + // ::= J # __export __fastcall + // The 'export' calling conventions are from a bygone era + // (*cough*Win16*cough*) when functions were declared for export with + // that keyword. (It didn't actually export them, it just made them so + // that they could be in a DLL and somebody from another module could call + // them.) + switch (T->getCallConv()) { + case CC_Default: + case CC_C: Out << 'A'; break; + case CC_X86ThisCall: Out << 'E'; break; + case CC_X86StdCall: Out << 'G'; break; + case CC_X86FastCall: Out << 'I'; break; + } +} +void MicrosoftCXXNameMangler::mangleThrowSpecification( + const FunctionProtoType *FT) { + // ::= Z # throw(...) (default) + // ::= @ # throw() or __declspec/__attribute__((nothrow)) + // ::= + + if (!FT->hasExceptionSpec() || FT->hasAnyExceptionSpec()) + Out << 'Z'; + else { + for (unsigned Exception = 0, NumExceptions = FT->getNumExceptions(); + Exception < NumExceptions; + ++Exception) + mangleType(FT->getExceptionType(Exception).getLocalUnqualifiedType()); + Out << '@'; + } +} + void MicrosoftMangleContext::mangleName(const NamedDecl *D, llvm::SmallVectorImpl &Name) { assert((isa(D) || isa(D)) && diff --git a/test/CodeGenCXX/mangle-ms.cpp b/test/CodeGenCXX/mangle-ms.cpp index 9748c107aa..f6101ea7eb 100644 --- a/test/CodeGenCXX/mangle-ms.cpp +++ b/test/CodeGenCXX/mangle-ms.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-apple-darwin10 | FileCheck %s +// RUN: %clang_cc1 -fms-extensions -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-apple-darwin10 | FileCheck %s // CHECK: @"\01?a@@3HA" // CHECK: @"\01?b@N@@3HA" @@ -13,6 +13,7 @@ namespace N { int b; } static int c; int _c(void) {return c;} +// CHECK: @"\01?_c@@YAHXZ" class foo { static const short d; @@ -26,3 +27,14 @@ const short foo::d = 0; volatile long foo::e; const volatile char foo::f = 'C'; +// Static functions are mangled, too. +// Also make sure calling conventions, arglists, and throw specs work. +static void __stdcall alpha(float a, double b) throw() {} +bool __fastcall beta(long long a, wchar_t b) throw(signed char, unsigned char) { +// CHECK: @"\01?beta@@YI_N_J_W@CE@" + alpha(0.f, 0.0); + return false; +} + +// CHECK: @"\01?alpha@@YGXMN@@" +