From 9fd2359ee3b140557b808e4b79bc73a3b9d62304 Mon Sep 17 00:00:00 2001 From: Charles Davis <cdavis@mines.edu> Date: Sat, 26 May 2012 23:12:19 +0000 Subject: [PATCH] Mangle template instantiations properly (as of VC 7.x) when compiling for the Microsoft Visual C++ ABI. Currently limited to type and integral non-type arguments. Based on a patch by Timur Iskhodzhanov! git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@157524 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/AST/MicrosoftMangle.cpp | 139 ++++++++++++++++++++++-- test/CodeGenCXX/mangle-ms-templates.cpp | 43 ++++++++ 2 files changed, 175 insertions(+), 7 deletions(-) create mode 100644 test/CodeGenCXX/mangle-ms-templates.cpp diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp index 6250f611986..6918ce48264 100644 --- a/lib/AST/MicrosoftMangle.cpp +++ b/lib/AST/MicrosoftMangle.cpp @@ -42,6 +42,7 @@ public: void mangleFunctionEncoding(const FunctionDecl *FD); void mangleVariableEncoding(const VarDecl *VD); void mangleNumber(int64_t Number); + void mangleNumber(const llvm::APSInt &Value); void mangleType(QualType T); private: @@ -54,6 +55,11 @@ private: void mangleOperatorName(OverloadedOperatorKind OO); void mangleQualifiers(Qualifiers Quals, bool IsMember); + void mangleUnscopedTemplateName(const TemplateDecl *ND); + void mangleTemplateInstantiationName(const TemplateDecl *TD, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + SourceLocation InstantiationLoc); void mangleObjCMethodName(const ObjCMethodDecl *MD); // Declare manglers for every type class. @@ -69,8 +75,12 @@ private: void mangleExtraDimensions(QualType T); void mangleFunctionClass(const FunctionDecl *FD); void mangleCallingConvention(const FunctionType *T, bool IsInstMethod = false); + void mangleIntegerLiteral(QualType T, const llvm::APSInt &Number); void mangleThrowSpecification(const FunctionProtoType *T); + void mangleTemplateArgs(const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, + SourceLocation InstantiationLoc); + }; /// MicrosoftMangleContext - Overrides the default MangleContext for the @@ -266,35 +276,92 @@ void MicrosoftCXXNameMangler::mangleName(const NamedDecl *ND) { } void MicrosoftCXXNameMangler::mangleNumber(int64_t Number) { - // <number> ::= [?] <decimal digit> # <= 9 - // ::= [?] <hex digit>+ @ # > 9; A = 0, B = 1, etc... + // <number> ::= [?] <decimal digit> # 1 <= Number <= 10 + // ::= [?] <hex digit>+ @ # 0 or > 9; A = 0, B = 1, etc... + // ::= [?] @ # 0 (alternate mangling, not emitted by VC) if (Number < 0) { Out << '?'; Number = -Number; } - if (Number >= 1 && Number <= 10) { + // Oddly enough, there's a special shorter mangling for 0, but Microsoft chose not + // to use it. Instead, 0 gets mangled as "A@". Oh well... + if (Number >= 1 && Number <= 10) Out << Number-1; - } else { + else { // We have to build up the encoding in reverse order, so it will come // out right when we write it out. char Encoding[16]; char *EndPtr = Encoding+sizeof(Encoding); char *CurPtr = EndPtr; - while (Number) { + do { *--CurPtr = 'A' + (Number % 16); Number /= 16; - } + } while (Number); Out.write(CurPtr, EndPtr-CurPtr); Out << '@'; } } +void MicrosoftCXXNameMangler::mangleNumber(const llvm::APSInt &Value) { + if (Value.isSigned() && Value.isNegative()) { + Out << '?'; + mangleNumber(llvm::APSInt(Value.abs())); + return; + } + if (Value.uge(1) && Value.ule(10)) + (Value-llvm::APSInt(llvm::APInt(Value.getBitWidth(), 1, Value.isSigned()))).print(Out, + false); + else { + // We have to build up the encoding in reverse order, so it will come + // out right when we write it out. + char Encoding[64]; + char *EndPtr = Encoding+sizeof(Encoding); + char *CurPtr = EndPtr; + llvm::APSInt Fifteen(Value.getBitWidth(), 15); + for (int i = 0, e = Value.getActiveBits() / 4; i != e; ++i) { + *--CurPtr = 'A' + Value.And(Fifteen).lshr(i*4).getLimitedValue(15); + Fifteen = Fifteen.shl(4); + }; + Out.write(CurPtr, EndPtr-CurPtr); + Out << '@'; + } +} + +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(); + } + + return 0; +} + void MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, DeclarationName Name) { // <unqualified-name> ::= <operator-name> // ::= <ctor-dtor-name> // ::= <source-name> + // ::= <template-name> + const TemplateArgumentList *TemplateArgs; + // Check if we have a template. + if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) { + mangleTemplateInstantiationName(TD, TemplateArgs->data(), TemplateArgs->size(), + ND->getLocation()); + return; + } + switch (Name.getNameKind()) { case DeclarationName::Identifier: { if (const IdentifierInfo *II = Name.getAsIdentifierInfo()) { @@ -364,7 +431,6 @@ MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, void MicrosoftCXXNameMangler::manglePostfix(const DeclContext *DC, bool NoFunction) { // <postfix> ::= <unqualified-name> [<postfix>] - // ::= <template-postfix> <template-args> [<postfix>] // ::= <template-param> // ::= <substitution> [<postfix>] @@ -523,10 +589,69 @@ void MicrosoftCXXNameMangler::mangleSourceName(const IdentifierInfo *II) { Out << II->getName() << '@'; } +void MicrosoftCXXNameMangler::mangleTemplateInstantiationName(const TemplateDecl *TD, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + SourceLocation InstantiationLoc) { + // <template-name> ::= <unscoped-template-name> <template-args> + // ::= <substitution> + // Always start with the unqualified name. + mangleUnscopedTemplateName(TD); + mangleTemplateArgs(TemplateArgs, NumTemplateArgs, InstantiationLoc); +} + void MicrosoftCXXNameMangler::mangleObjCMethodName(const ObjCMethodDecl *MD) { Context.mangleObjCMethodName(MD, Out); } +void +MicrosoftCXXNameMangler::mangleUnscopedTemplateName(const TemplateDecl *TD) { + // <unscoped-template-name> ::= ?$ <unqualified-name> + Out << "?$"; + mangleUnqualifiedName(TD); +} + +void +MicrosoftCXXNameMangler::mangleIntegerLiteral(QualType T, const llvm::APSInt &Value) { + // <integer-literal> ::= $0 <number> + Out << "$0"; + // Make sure booleans are encoded as 0/1. + if (T->isBooleanType()) + Out << (Value.getBoolValue() ? "0" : "A@"); + else + mangleNumber(Value); +} + +void +MicrosoftCXXNameMangler::mangleTemplateArgs(const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + SourceLocation InstantiationLoc) { + // <template-args> ::= {<type> | <integer-literal>}+ @ + for (unsigned int i = 0; i < NumTemplateArgs; ++i) { + const TemplateArgument &TA = TemplateArgs[i]; + switch (TA.getKind()) { + case TemplateArgument::Null: + llvm_unreachable("Can't mangle null template arguments!"); + case TemplateArgument::Type: + mangleType(TA.getAsType()); + break; + case TemplateArgument::Integral: + mangleIntegerLiteral(TA.getIntegralType(), *TA.getAsIntegral()); + break; + default: { + // Issue a diagnostic. + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot yet mangle this %select{null|type|pointer/reference|integral|template|" + "template pack expansion|expression|parameter pack}0 template argument"); + Diags.Report(InstantiationLoc, DiagID) + << TA.getKind(); + } + } + } + Out << '@'; +} + void MicrosoftCXXNameMangler::mangleQualifiers(Qualifiers Quals, bool IsMember) { // <cvr-qualifiers> ::= [E] [F] [I] <base-cvr-qualifiers> diff --git a/test/CodeGenCXX/mangle-ms-templates.cpp b/test/CodeGenCXX/mangle-ms-templates.cpp new file mode 100644 index 00000000000..357cc3b0e9f --- /dev/null +++ b/test/CodeGenCXX/mangle-ms-templates.cpp @@ -0,0 +1,43 @@ +// RUN: %clang_cc1 -fms-extensions -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s + +template<typename T> +class Class { + public: + void method() {} +}; + +class Typename { }; + +template<typename T> +class Nested { }; + +template<bool flag> +class BoolTemplate { + public: + BoolTemplate() {} +}; + +void template_mangling() { + Class<Typename> c1; + c1.method(); +// CHECK: call {{.*}} @"\01?method@?$Class@VTypename@@@@QAEXXZ" + + Class<Nested<Typename> > c2; + c2.method(); +// CHECK: call {{.*}} @"\01?method@?$Class@V?$Nested@VTypename@@@@@@QAEXXZ" + + BoolTemplate<false> _false; +// CHECK: call {{.*}} @"\01??0?$BoolTemplate@$0A@@@QAE@XZ" + + BoolTemplate<true> _true; +// CHECK: call {{.*}} @"\01??0?$BoolTemplate@$00@@QAE@XZ" +} + +namespace space { + template<class T> const T& foo(const T& l) { return l; } +} +// CHECK: "\01??$foo@H@space@@YAABHABH@Z" + +void use() { + space::foo(42); +} -- GitLab