From: Charles Davis Date: Sat, 26 Jun 2010 03:50:05 +0000 (+0000) Subject: Mangle pointer and (lvalue) reference types in the Microsoft C++ Mangler. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3a0d41d29192ff42870310e33800939f4e34bb55;p=clang Mangle pointer and (lvalue) reference types in the Microsoft C++ Mangler. Also, fix mangling of throw specs. Turns out MSVC totally ignores throw specs when mangling names. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@106937 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp index ddf32ece58..18e648787e 100644 --- a/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/lib/CodeGen/MicrosoftCXXABI.cpp @@ -69,7 +69,7 @@ private: #include "clang/AST/TypeNodes.def" void mangleType(const TagType*); - void mangleType(const FunctionType *T, bool IsStructor); + void mangleType(const FunctionType *T, bool IsStructor, bool IsInstMethod); void mangleFunctionClass(const FunctionDecl *FD); void mangleCallingConvention(const FunctionType *T); void mangleThrowSpecification(const FunctionProtoType *T); @@ -202,11 +202,13 @@ void MicrosoftCXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) { // 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()); + const FunctionProtoType *FT = cast(FD->getType()); - bool InStructor = false; + bool InStructor = false, InInstMethod = false; const CXXMethodDecl *MD = dyn_cast(FD); if (MD) { + if (MD->isInstance()) + InInstMethod = true; if (isa(MD) || isa(MD)) InStructor = true; } @@ -214,29 +216,7 @@ void MicrosoftCXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) { // 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); + mangleType(FT, InStructor, InInstMethod); } void MicrosoftCXXNameMangler::mangleVariableEncoding(const VarDecl *VD) { @@ -263,9 +243,17 @@ void MicrosoftCXXNameMangler::mangleVariableEncoding(const VarDecl *VD) { Out << '4'; // Now mangle the type. // ::= + // ::= A # pointers and references + // Pointers and references are odd. The type of 'int * const foo;' gets + // mangled as 'QAHA' instead of 'PAHB', for example. QualType Ty = VD->getType(); - mangleType(Ty.getLocalUnqualifiedType()); - mangleQualifiers(Ty.getLocalQualifiers(), false); + if (Ty->isPointerType() || Ty->isReferenceType()) { + mangleType(Ty); + Out << 'A'; + } else { + mangleType(Ty.getLocalUnqualifiedType()); + mangleQualifiers(Ty.getLocalQualifiers(), false); + } } void MicrosoftCXXNameMangler::mangleName(const NamedDecl *ND) { @@ -642,6 +630,32 @@ void MicrosoftCXXNameMangler::mangleType(QualType T) { // Only operate on the canonical type! T = getASTContext().getCanonicalType(T); + Qualifiers Quals = T.getLocalQualifiers(); + if (Quals) { + // We have to mangle these now, while we still have enough information. + // ::= P # pointer + // ::= Q # const pointer + // ::= R # volatile pointer + // ::= S # const volatile pointer + if (T->isPointerType()) { + if (!Quals.hasVolatile()) { + Out << 'Q'; + } else { + if (!Quals.hasConst()) + Out << 'R'; + else + Out << 'S'; + } + } else + // Just emit qualifiers like normal. + // NB: When we mangle a pointer/reference type, and the pointee + // type has no qualifiers, the lack of qualifier gets mangled + // in there. + mangleQualifiers(Quals, false); + } + else if (T->isPointerType()) { + Out << 'P'; + } switch (T->getTypeClass()) { #define ABSTRACT_TYPE(CLASS, PARENT) #define NON_CANONICAL_TYPE(CLASS, PARENT) \ @@ -659,6 +673,12 @@ return; case Type::Record: mangleType(static_cast(T.getTypePtr())); break; + case Type::Pointer: + mangleType(static_cast(T.getTypePtr())); + break; + case Type::LValueReference: + mangleType(static_cast(T.getTypePtr())); + break; default: assert(false && "Don't know how to mangle this type!"); break; @@ -743,22 +763,29 @@ 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); + // I'll probably have mangleType(MemberPointerType) call + mangleType(T, false, 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); - + bool IsStructor, + bool IsInstMethod) { + // ::= + // 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 this is a C++ instance method, mangle the CVR qualifiers for the + // this pointer. + if (IsInstMethod) + mangleQualifiers(Qualifiers::fromCVRMask(Proto->getTypeQuals()), false); + + mangleCallingConvention(T); + + // ::= + // ::= @ # structors (they have no declared return type) if (IsStructor) Out << '@'; else @@ -871,15 +898,10 @@ void MicrosoftCXXNameMangler::mangleThrowSpecification( // ::= 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 << '@'; - } + // NOTE: Since the Microsoft compiler ignores throw specifications, they are + // all actually mangled as 'Z'. (They're ignored because their associated + // functionality isn't implemented, and probably never will be.) + Out << 'Z'; } // ::= | | | @@ -913,6 +935,27 @@ void MicrosoftCXXNameMangler::mangleType(const TagType *T) { mangleName(T->getDecl()); } +// ::= +// ::= +void MicrosoftCXXNameMangler::mangleType(const PointerType *T) { + QualType PointeeTy = T->getPointeeType(); + if (!PointeeTy.hasLocalQualifiers()) + // Lack of qualifiers is mangled as 'A'. + Out << 'A'; + mangleType(PointeeTy); +} + +// ::= +// ::= A +void MicrosoftCXXNameMangler::mangleType(const LValueReferenceType *T) { + Out << 'A'; + QualType PointeeTy = T->getPointeeType(); + if (!PointeeTy.hasLocalQualifiers()) + // Lack of qualifiers is mangled as 'A'. + Out << 'A'; + mangleType(PointeeTy); +} + 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 a528054d8d..d0bd4a967d 100644 --- a/test/CodeGenCXX/mangle-ms.cpp +++ b/test/CodeGenCXX/mangle-ms.cpp @@ -7,6 +7,7 @@ // CHECK: @"\01?e@foo@@1JC" // CHECK: @"\01?f@foo@@2DD" // CHECK: @"\01?g@bar@@2HA" +// CHECK: @"\01?h@@3QAHA" int a; @@ -50,18 +51,23 @@ const volatile char foo::f = 'C'; int bar::g; +extern int * const h = &a; + // 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@" +// CHECK: @"\01?beta@@YI_N_J_W@Z" alpha(0.f, 0.0); return false; } -// CHECK: @"\01?alpha@@YGXMN@@" +// CHECK: @"\01?alpha@@YGXMN@Z" // Make sure tag-type mangling works. void gamma(class foo, struct bar, union baz, enum quux) {} // CHECK: @"\01?gamma@@YAXVfoo@@Ubar@@Tbaz@@W4quux@@@Z" +// Make sure pointer/reference-type mangling works. +void delta(int * const a, const long &) {} +// CHECK: @"\01?delta@@YAXQAHABJ@Z"