From b70d1c32ca62d072b3f4a5d4628fdcf692cbf2f0 Mon Sep 17 00:00:00 2001 From: Peter Collingbourne Date: Thu, 25 Apr 2013 04:25:40 +0000 Subject: [PATCH] [ms-cxxabi] Fix a number of bugs in the mangler. This includes the following fixes: - Implement 4 subtly different variants of qualifier mangling and use them in what I believe are the right places. - Fix handling of array types. Previously we were always decaying them, which is wrong if the type appears as a template argument, pointee, referent etc. Fixes PR13182. Differential Revision: http://llvm-reviews.chandlerc.com/D709 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@180250 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/AST/MicrosoftMangle.cpp | 189 +++++++++--------- test/CodeGenCXX/mangle-ms-arg-qualifiers.cpp | 45 +++++ .../mangle-ms-return-qualifiers.cpp | 9 + test/CodeGenCXX/mangle-ms-templates.cpp | 32 +-- test/CodeGenCXX/mangle-ms.cpp | 7 +- 5 files changed, 173 insertions(+), 109 deletions(-) diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp index 9cd6bac971..1785063d7b 100644 --- a/lib/AST/MicrosoftMangle.cpp +++ b/lib/AST/MicrosoftMangle.cpp @@ -59,6 +59,8 @@ class MicrosoftCXXNameMangler { ASTContext &getASTContext() const { return Context.getASTContext(); } public: + enum QualifierMangleMode { QMM_Drop, QMM_Mangle, QMM_Escape, QMM_Result }; + MicrosoftCXXNameMangler(MangleContext &C, raw_ostream &Out_) : Context(C), Out(Out_), Structor(0), StructorType(-1), @@ -78,7 +80,8 @@ public: void mangleVariableEncoding(const VarDecl *VD); void mangleNumber(int64_t Number); void mangleNumber(const llvm::APSInt &Value); - void mangleType(QualType T, SourceRange Range, bool MangleQualifiers = true); + void mangleType(QualType T, SourceRange Range, + QualifierMangleMode QMM = QMM_Mangle); private: void disableBackReferences() { UseNameBackReferences = false; } @@ -112,10 +115,10 @@ private: #undef TYPE void mangleType(const TagType*); - void mangleType(const FunctionType *T, const FunctionDecl *D, - bool IsStructor, bool IsInstMethod); - void mangleType(const ArrayType *T, bool IsGlobal); - void mangleExtraDimensions(QualType T); + void mangleFunctionType(const FunctionType *T, const FunctionDecl *D, + bool IsStructor, bool IsInstMethod); + void mangleDecayedArrayType(const ArrayType *T, bool IsGlobal); + void mangleArrayType(const ArrayType *T, Qualifiers Quals); void mangleFunctionClass(const FunctionDecl *FD); void mangleCallingConvention(const FunctionType *T, bool IsInstMethod = false); void mangleIntegerLiteral(const llvm::APSInt &Number, bool IsBoolean); @@ -264,7 +267,7 @@ void MicrosoftCXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) { // First, the function class. mangleFunctionClass(FD); - mangleType(FT, FD, InStructor, InInstMethod); + mangleFunctionType(FT, FD, InStructor, InInstMethod); } void MicrosoftCXXNameMangler::mangleVariableEncoding(const VarDecl *VD) { @@ -297,14 +300,17 @@ void MicrosoftCXXNameMangler::mangleVariableEncoding(const VarDecl *VD) { TypeLoc TL = VD->getTypeSourceInfo()->getTypeLoc(); QualType Ty = TL.getType(); if (Ty->isPointerType() || Ty->isReferenceType()) { - mangleType(Ty, TL.getSourceRange()); + mangleType(Ty, TL.getSourceRange(), QMM_Drop); mangleQualifiers(Ty->getPointeeType().getQualifiers(), false); } else if (const ArrayType *AT = getASTContext().getAsArrayType(Ty)) { // Global arrays are funny, too. - mangleType(AT, true); - mangleQualifiers(Ty.getQualifiers(), false); + mangleDecayedArrayType(AT, true); + if (AT->getElementType()->isArrayType()) + Out << 'A'; + else + mangleQualifiers(Ty.getQualifiers(), false); } else { - mangleType(Ty.getLocalUnqualifiedType(), TL.getSourceRange()); + mangleType(Ty, TL.getSourceRange(), QMM_Drop); mangleQualifiers(Ty.getLocalQualifiers(), false); } } @@ -826,9 +832,7 @@ MicrosoftCXXNameMangler::mangleTemplateArgs(const TemplateDecl *TD, llvm_unreachable("Can't mangle null template arguments!"); case TemplateArgument::Type: { QualType T = TA.getAsType(); - if (T.hasQualifiers()) - Out << "$$C"; - mangleType(T, SourceRange()); + mangleType(T, SourceRange(), QMM_Escape); break; } case TemplateArgument::Declaration: @@ -968,7 +972,14 @@ void MicrosoftCXXNameMangler::mangleArgumentType(QualType T, if (Found == TypeBackReferences.end()) { size_t OutSizeBefore = Out.GetNumBytesInBuffer(); - mangleType(T, Range, false); + if (const ArrayType *AT = getASTContext().getAsArrayType(T)) { + mangleDecayedArrayType(AT, false); + } else if (const FunctionType *FT = T->getAs()) { + Out << "P6"; + mangleFunctionType(FT, 0, false, false); + } else { + mangleType(T, Range, QMM_Drop); + } // See if it's worth creating a back reference. // Only types longer than 1 character are considered @@ -984,28 +995,53 @@ void MicrosoftCXXNameMangler::mangleArgumentType(QualType T, } void MicrosoftCXXNameMangler::mangleType(QualType T, SourceRange Range, - bool MangleQualifiers) { + QualifierMangleMode QMM) { // Only operate on the canonical type! T = getASTContext().getCanonicalType(T); - Qualifiers Quals = T.getLocalQualifiers(); - // We have to mangle these now, while we still have enough information. - if (T->isAnyPointerType() || T->isMemberPointerType() || - T->isBlockPointerType()) { - manglePointerQualifiers(Quals); - } else if (Quals && MangleQualifiers) { - mangleQualifiers(Quals, false); + + if (const ArrayType *AT = dyn_cast(T)) { + if (QMM == QMM_Mangle) + Out << 'A'; + else if (QMM == QMM_Escape || QMM == QMM_Result) + Out << "$$B"; + mangleArrayType(AT, Quals); + return; } - SplitQualType split = T.split(); - const Type *ty = split.Ty; + bool IsPointer = T->isAnyPointerType() || T->isMemberPointerType() || + T->isBlockPointerType(); - // If we're mangling a qualified array type, push the qualifiers to - // the element type. - if (split.Quals && isa(T)) { - ty = Context.getASTContext().getAsArrayType(T); + switch (QMM) { + case QMM_Drop: + break; + case QMM_Mangle: + if (const FunctionType *FT = dyn_cast(T)) { + Out << '6'; + mangleFunctionType(FT, 0, false, false); + return; + } + mangleQualifiers(Quals, false); + break; + case QMM_Escape: + if (!IsPointer && Quals) { + Out << "$$C"; + mangleQualifiers(Quals, false); + } + break; + case QMM_Result: + if ((!IsPointer && Quals) || isa(T)) { + Out << '?'; + mangleQualifiers(Quals, false); + } + break; } + // We have to mangle these now, while we still have enough information. + if (IsPointer) + manglePointerQualifiers(Quals); + const Type *ty = T.getTypePtr(); + switch (ty->getTypeClass()) { #define ABSTRACT_TYPE(CLASS, PARENT) #define NON_CANONICAL_TYPE(CLASS, PARENT) \ @@ -1115,17 +1151,17 @@ void MicrosoftCXXNameMangler::mangleType(const FunctionProtoType *T, // structor type. // FIXME: This may not be lambda-friendly. Out << "$$A6"; - mangleType(T, NULL, false, false); + mangleFunctionType(T, NULL, false, false); } void MicrosoftCXXNameMangler::mangleType(const FunctionNoProtoType *T, SourceRange) { llvm_unreachable("Can't mangle K&R function prototypes"); } -void MicrosoftCXXNameMangler::mangleType(const FunctionType *T, - const FunctionDecl *D, - bool IsStructor, - bool IsInstMethod) { +void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T, + const FunctionDecl *D, + bool IsStructor, + bool IsInstMethod) { // ::= // const FunctionProtoType *Proto = cast(T); @@ -1151,21 +1187,7 @@ void MicrosoftCXXNameMangler::mangleType(const FunctionType *T, } Out << '@'; } else { - QualType Result = Proto->getResultType(); - const Type* RT = Result.getTypePtr(); - if (!RT->isAnyPointerType() && !RT->isReferenceType()) { - if (Result.hasQualifiers() || !RT->isBuiltinType()) - Out << '?'; - if (!RT->isBuiltinType() && !Result.hasQualifiers()) { - // Lack of qualifiers for user types is mangled as 'A'. - Out << 'A'; - } - } - - // FIXME: Get the source range for the result type. Or, better yet, - // implement the unimplemented stuff so we don't need accurate source - // location info anymore :). - mangleType(Result, SourceRange()); + mangleType(Proto->getResultType(), SourceRange(), QMM_Result); } // ::= X # void @@ -1360,7 +1382,8 @@ void MicrosoftCXXNameMangler::mangleType(const TagType *T) { // It's supposed to be the other way around, but for some strange reason, it // isn't. Today this behavior is retained for the sole purpose of backwards // compatibility. -void MicrosoftCXXNameMangler::mangleType(const ArrayType *T, bool IsGlobal) { +void MicrosoftCXXNameMangler::mangleDecayedArrayType(const ArrayType *T, + bool IsGlobal) { // This isn't a recursive mangling, so now we have to do it all in this // one call. if (IsGlobal) { @@ -1368,25 +1391,27 @@ void MicrosoftCXXNameMangler::mangleType(const ArrayType *T, bool IsGlobal) { } else { Out << 'Q'; } - mangleExtraDimensions(T->getElementType()); + mangleType(T->getElementType(), SourceRange()); } void MicrosoftCXXNameMangler::mangleType(const ConstantArrayType *T, SourceRange) { - mangleType(cast(T), false); + llvm_unreachable("Should have been special cased"); } void MicrosoftCXXNameMangler::mangleType(const VariableArrayType *T, SourceRange) { - mangleType(cast(T), false); + llvm_unreachable("Should have been special cased"); } void MicrosoftCXXNameMangler::mangleType(const DependentSizedArrayType *T, SourceRange) { - mangleType(cast(T), false); + llvm_unreachable("Should have been special cased"); } void MicrosoftCXXNameMangler::mangleType(const IncompleteArrayType *T, SourceRange) { - mangleType(cast(T), false); + llvm_unreachable("Should have been special cased"); } -void MicrosoftCXXNameMangler::mangleExtraDimensions(QualType ElementTy) { +void MicrosoftCXXNameMangler::mangleArrayType(const ArrayType *T, + Qualifiers Quals) { + QualType ElementTy(T, 0); SmallVector Dimensions; for (;;) { if (const ConstantArrayType *CAT = @@ -1412,20 +1437,20 @@ void MicrosoftCXXNameMangler::mangleExtraDimensions(QualType ElementTy) { Diags.Report(DSAT->getSizeExpr()->getExprLoc(), DiagID) << DSAT->getBracketsRange(); return; - } else if (ElementTy->isIncompleteArrayType()) continue; - else break; - } - mangleQualifiers(ElementTy.getQualifiers(), false); - // If there are any additional dimensions, mangle them now. - if (Dimensions.size() > 0) { - Out << 'Y'; - // ::= # number of extra dimensions - mangleNumber(Dimensions.size()); - for (unsigned Dim = 0; Dim < Dimensions.size(); ++Dim) { - mangleNumber(Dimensions[Dim].getLimitedValue()); + } else if (const IncompleteArrayType *IAT = + getASTContext().getAsIncompleteArrayType(ElementTy)) { + Dimensions.push_back(llvm::APInt(32, 0)); + ElementTy = IAT->getElementType(); } + else break; } - mangleType(ElementTy.getLocalUnqualifiedType(), SourceRange()); + Out << 'Y'; + // ::= # number of extra dimensions + mangleNumber(Dimensions.size()); + for (unsigned Dim = 0; Dim < Dimensions.size(); ++Dim) + mangleNumber(Dimensions[Dim].getLimitedValue()); + mangleType(getASTContext().getQualifiedType(ElementTy.getTypePtr(), Quals), + SourceRange(), QMM_Escape); } // ::= @@ -1437,11 +1462,11 @@ void MicrosoftCXXNameMangler::mangleType(const MemberPointerType *T, if (const FunctionProtoType *FPT = PointeeType->getAs()) { Out << '8'; mangleName(T->getClass()->castAs()->getDecl()); - mangleType(FPT, NULL, false, true); + mangleFunctionType(FPT, NULL, false, true); } else { mangleQualifiers(PointeeType.getQualifiers(), true); mangleName(T->getClass()->castAs()->getDecl()); - mangleType(PointeeType.getLocalUnqualifiedType(), Range); + mangleType(PointeeType, Range, QMM_Drop); } } @@ -1469,17 +1494,7 @@ void MicrosoftCXXNameMangler::mangleType( void MicrosoftCXXNameMangler::mangleType(const PointerType *T, SourceRange Range) { QualType PointeeTy = T->getPointeeType(); - if (PointeeTy->isArrayType()) { - // Pointers to arrays are mangled like arrays. - mangleExtraDimensions(PointeeTy); - } else if (const FunctionType *FT = PointeeTy->getAs()) { - // Function pointers are special. - Out << '6'; - mangleType(FT, NULL, false, false); - } else { - mangleQualifiers(PointeeTy.getQualifiers(), false); - mangleType(PointeeTy, Range, false); - } + mangleType(PointeeTy, Range); } void MicrosoftCXXNameMangler::mangleType(const ObjCObjectPointerType *T, SourceRange Range) { @@ -1493,11 +1508,7 @@ void MicrosoftCXXNameMangler::mangleType(const ObjCObjectPointerType *T, void MicrosoftCXXNameMangler::mangleType(const LValueReferenceType *T, SourceRange Range) { Out << 'A'; - QualType PointeeTy = T->getPointeeType(); - if (!PointeeTy.hasQualifiers()) - // Lack of qualifiers is mangled as 'A'. - Out << 'A'; - mangleType(PointeeTy, Range); + mangleType(T->getPointeeType(), Range); } // ::= @@ -1505,11 +1516,7 @@ void MicrosoftCXXNameMangler::mangleType(const LValueReferenceType *T, void MicrosoftCXXNameMangler::mangleType(const RValueReferenceType *T, SourceRange Range) { Out << "$$Q"; - QualType PointeeTy = T->getPointeeType(); - if (!PointeeTy.hasQualifiers()) - // Lack of qualifiers is mangled as 'A'. - Out << 'A'; - mangleType(PointeeTy, Range); + mangleType(T->getPointeeType(), Range); } void MicrosoftCXXNameMangler::mangleType(const ComplexType *T, @@ -1591,7 +1598,7 @@ void MicrosoftCXXNameMangler::mangleType(const BlockPointerType *T, Out << "_E"; QualType pointee = T->getPointeeType(); - mangleType(pointee->castAs(), NULL, false, false); + mangleFunctionType(pointee->castAs(), NULL, false, false); } void MicrosoftCXXNameMangler::mangleType(const InjectedClassNameType *T, diff --git a/test/CodeGenCXX/mangle-ms-arg-qualifiers.cpp b/test/CodeGenCXX/mangle-ms-arg-qualifiers.cpp index 0ac9b3f121..d03ba52649 100644 --- a/test/CodeGenCXX/mangle-ms-arg-qualifiers.cpp +++ b/test/CodeGenCXX/mangle-ms-arg-qualifiers.cpp @@ -60,6 +60,51 @@ void foo_pcrbd(const char * volatile* x) {} void foo_pcrcd(volatile char * volatile* x) {} // CHECK: "\01?foo_pcrcd@@YAXPCRCD@Z" +void foo_aad(char &x) {} +// CHECK: "\01?foo_aad@@YAXAAD@Z" + +void foo_abd(const char &x) {} +// CHECK: "\01?foo_abd@@YAXABD@Z" + +void foo_aapad(char *&x) {} +// CHECK: "\01?foo_aapad@@YAXAAPAD@Z" + +void foo_aapbd(const char *&x) {} +// CHECK: "\01?foo_aapbd@@YAXAAPBD@Z" + +void foo_abqad(char * const &x) {} +// CHECK: "\01?foo_abqad@@YAXABQAD@Z" + +void foo_abqbd(const char * const &x) {} +// CHECK: "\01?foo_abqbd@@YAXABQBD@Z" + +void foo_aay144h(int (&x)[5][5]) {} +// CHECK: "\01?foo_aay144h@@YAXAAY144H@Z" + +void foo_aay144cbh(const int (&x)[5][5]) {} +// CHECK: "\01?foo_aay144cbh@@YAXAAY144$$CBH@Z" + +void foo_qay144h(int (&&x)[5][5]) {} +// CHECK: "\01?foo_qay144h@@YAX$$QAY144H@Z" + +void foo_qay144cbh(const int (&&x)[5][5]) {} +// CHECK: "\01?foo_qay144cbh@@YAX$$QAY144$$CBH@Z" + +void foo_p6ahxz(int x()) {} +// CHECK: "\01?foo_p6ahxz@@YAXP6AHXZ@Z" + +void foo_a6ahxz(int (&x)()) {} +// CHECK: "\01?foo_a6ahxz@@YAXA6AHXZ@Z" + +void foo_q6ahxz(int (&&x)()) {} +// CHECK: "\01?foo_q6ahxz@@YAX$$Q6AHXZ@Z" + +void foo_qay04h(int x[5][5]) {} +// CHECK: "\01?foo_qay04h@@YAXQAY04H@Z" + +void foo_qay04cbh(const int x[5][5]) {} +// CHECK: "\01?foo_qay04cbh@@YAXQAY04$$CBH@Z" + typedef double Vector[3]; void foo(Vector*) {} diff --git a/test/CodeGenCXX/mangle-ms-return-qualifiers.cpp b/test/CodeGenCXX/mangle-ms-return-qualifiers.cpp index 63bc4a9eb3..87e04c645e 100644 --- a/test/CodeGenCXX/mangle-ms-return-qualifiers.cpp +++ b/test/CodeGenCXX/mangle-ms-return-qualifiers.cpp @@ -155,6 +155,15 @@ const volatile struct S* f5() { return 0; } struct S& f6() { return *(struct S*)0; } // CHECK: "\01?f6@@YAAAUS@@XZ" +struct S* const f7() { return 0; } +// CHECK: "\01?f7@@YAQAUS@@XZ" + +int S::* f8() { return 0; } +// CHECK: "\01?f8@@YAPQS@@HXZ" + +int S::* const f9() { return 0; } +// CHECK: "\01?f9@@YAQQS@@HXZ" + typedef int (*function_pointer)(int); function_pointer g1() { return 0; } diff --git a/test/CodeGenCXX/mangle-ms-templates.cpp b/test/CodeGenCXX/mangle-ms-templates.cpp index 7b7f30bb72..10e68248dc 100644 --- a/test/CodeGenCXX/mangle-ms-templates.cpp +++ b/test/CodeGenCXX/mangle-ms-templates.cpp @@ -3,7 +3,7 @@ template class Class { public: - void method() {} + Class() {} }; class Typename { }; @@ -32,24 +32,30 @@ class BoolTemplate { void template_mangling() { Class c1; - c1.method(); -// CHECK: call {{.*}} @"\01?method@?$Class@VTypename@@@@QAEXXZ" +// CHECK: call {{.*}} @"\01??0?$Class@VTypename@@@@QAE@XZ" Class c1_const; +// CHECK: call {{.*}} @"\01??0?$Class@$$CBVTypename@@@@QAE@XZ" Class c1_volatile; +// CHECK: call {{.*}} @"\01??0?$Class@$$CCVTypename@@@@QAE@XZ" Class c1_cv; - c1_const.method(); - c1_volatile.method(); - c1_cv.method(); -// Types with qualifiers have an extra $$C escape when used as template -// arguments. Not sure why. -// CHECK: call {{.*}} @"\01?method@?$Class@$$CBVTypename@@@@QAEXXZ" -// CHECK: call {{.*}} @"\01?method@?$Class@$$CCVTypename@@@@QAEXXZ" -// CHECK: call {{.*}} @"\01?method@?$Class@$$CDVTypename@@@@QAEXXZ" +// CHECK: call {{.*}} @"\01??0?$Class@$$CDVTypename@@@@QAE@XZ" Class > c2; - c2.method(); -// CHECK: call {{.*}} @"\01?method@?$Class@V?$Nested@VTypename@@@@@@QAEXXZ" +// CHECK: call {{.*}} @"\01??0?$Class@V?$Nested@VTypename@@@@@@QAE@XZ" + + Class c_intpc; +// CHECK: call {{.*}} @"\01??0?$Class@QAH@@QAE@XZ" + Class c_ft; +// CHECK: call {{.*}} @"\01??0?$Class@$$A6AHXZ@@QAE@XZ" + Class c_inti; +// CHECK: call {{.*}} @"\01??0?$Class@$$BY0A@H@@QAE@XZ" + Class c_int5; +// CHECK: call {{.*}} @"\01??0?$Class@$$BY04H@@QAE@XZ" + Class c_intc5; +// CHECK: call {{.*}} @"\01??0?$Class@$$BY04$$CBH@@QAE@XZ" + Class c_intpc5; +// CHECK: call {{.*}} @"\01??0?$Class@$$BY04QAH@@QAE@XZ" BoolTemplate _false; // CHECK: call {{.*}} @"\01??0?$BoolTemplate@$0A@@@QAE@XZ" diff --git a/test/CodeGenCXX/mangle-ms.cpp b/test/CodeGenCXX/mangle-ms.cpp index 6441d67a75..1b98a84823 100644 --- a/test/CodeGenCXX/mangle-ms.cpp +++ b/test/CodeGenCXX/mangle-ms.cpp @@ -17,11 +17,8 @@ // CHECK: @"\01?l@@3P8foo@@AEHH@ZA" // CHECK: @"\01?color1@@3PANA" // CHECK: @"\01?color2@@3QBNB" - -// FIXME: The following three tests currently fail, see http://llvm.org/PR13182 -// Replace "CHECK-NOT" with "CHECK" when it is fixed. -// CHECK-NOT: @"\01?color3@@3QAY02$$CBNA" -// CHECK-NOT: @"\01?color4@@3QAY02$$CBNA" +// CHECK: @"\01?color3@@3QAY02$$CBNA" +// CHECK: @"\01?color4@@3QAY02$$CBNA" int a; -- 2.40.0