Index: cfe/trunk/include/clang/AST/ASTContext.h =================================================================== --- cfe/trunk/include/clang/AST/ASTContext.h +++ cfe/trunk/include/clang/AST/ASTContext.h @@ -66,6 +66,7 @@ class UnresolvedSetIterator; class UsingDecl; class UsingShadowDecl; + class VTableContextBase; namespace Builtin { class Context; } @@ -1731,6 +1732,8 @@ bool isNearlyEmpty(const CXXRecordDecl *RD) const; + VTableContextBase *getVTableContext(); + MangleContext *createMangleContext(); void DeepCollectObjCIvars(const ObjCInterfaceDecl *OI, bool leafClass, @@ -2292,6 +2295,8 @@ void ReleaseDeclContextMaps(); llvm::OwningPtr AllParents; + + llvm::OwningPtr VTContext; }; /// \brief Utility function for constructing a nullary selector. Index: cfe/trunk/include/clang/AST/DeclCXX.h =================================================================== --- cfe/trunk/include/clang/AST/DeclCXX.h +++ cfe/trunk/include/clang/AST/DeclCXX.h @@ -1605,6 +1605,18 @@ /// \brief Calculate what the inheritance model would be for this class. MSInheritanceAttr::Spelling calculateInheritanceModel() const; + /// In the Microsoft C++ ABI, use zero for the field offset of a null data + /// member pointer if we can guarantee that zero is not a valid field offset, + /// or if the member pointer has multiple fields. Polymorphic classes have a + /// vfptr at offset zero, so we can use zero for null. If there are multiple + /// fields, we can use zero even if it is a valid field offset because + /// null-ness testing will check the other fields. + bool nullFieldOffsetIsZero() const { + return !MSInheritanceAttr::hasOnlyOneField(/*IsMemberFunction=*/false, + getMSInheritanceModel()) || + (hasDefinition() && isPolymorphic()); + } + /// \brief Determine whether this lambda expression was known to be dependent /// at the time it was created, even if its context does not appear to be /// dependent. Index: cfe/trunk/include/clang/AST/Mangle.h =================================================================== --- cfe/trunk/include/clang/AST/Mangle.h +++ cfe/trunk/include/clang/AST/Mangle.h @@ -200,7 +200,6 @@ raw_ostream &Out) = 0; virtual void mangleVirtualMemPtrThunk(const CXXMethodDecl *MD, - uint64_t OffsetInVFTable, raw_ostream &) = 0; static bool classof(const MangleContext *C) { Index: cfe/trunk/include/clang/Basic/Attr.td =================================================================== --- cfe/trunk/include/clang/Basic/Attr.td +++ cfe/trunk/include/clang/Basic/Attr.td @@ -1401,6 +1401,28 @@ Keyword<"__multiple_inheritance">, Keyword<"__virtual_inheritance">, Keyword<"__unspecified_inheritance">]; + let AdditionalMembers = [{ + static bool hasVBPtrOffsetField(Spelling Inheritance) { + return Inheritance == Keyword_unspecified_inheritance; + } + + // Only member pointers to functions need a this adjustment, since it can be + // combined with the field offset for data pointers. + static bool hasNVOffsetField(bool IsMemberFunction, Spelling Inheritance) { + return IsMemberFunction && Inheritance >= Keyword_multiple_inheritance; + } + + static bool hasVBTableOffsetField(Spelling Inheritance) { + return Inheritance >= Keyword_virtual_inheritance; + } + + static bool hasOnlyOneField(bool IsMemberFunction, + Spelling Inheritance) { + if (IsMemberFunction) + return Inheritance <= Keyword_single_inheritance; + return Inheritance <= Keyword_multiple_inheritance; + } + }]; } def Unaligned : IgnoredAttr { Index: cfe/trunk/lib/AST/ASTContext.cpp =================================================================== --- cfe/trunk/lib/AST/ASTContext.cpp +++ cfe/trunk/lib/AST/ASTContext.cpp @@ -29,6 +29,7 @@ #include "clang/AST/RecordLayout.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/TypeLoc.h" +#include "clang/AST/VTableBuilder.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" @@ -7952,6 +7953,16 @@ return ABI->isNearlyEmpty(RD); } +VTableContextBase *ASTContext::getVTableContext() { + if (!VTContext.get()) { + if (Target->getCXXABI().isMicrosoft()) + VTContext.reset(new MicrosoftVTableContext(*this)); + else + VTContext.reset(new ItaniumVTableContext(*this)); + } + return VTContext.get(); +} + MangleContext *ASTContext::createMangleContext() { switch (Target->getCXXABI().getKind()) { case TargetCXXABI::GenericAArch64: Index: cfe/trunk/lib/AST/MicrosoftCXXABI.cpp =================================================================== --- cfe/trunk/lib/AST/MicrosoftCXXABI.cpp +++ cfe/trunk/lib/AST/MicrosoftCXXABI.cpp @@ -136,14 +136,14 @@ // // offset. // int NonVirtualBaseAdjustment; // +// // The offset of the vb-table pointer within the object. Only needed for +// // incomplete types. +// int VBPtrOffset; +// // // An offset within the vb-table that selects the virtual base containing // // the member. Loading from this offset produces a new offset that is // // added to the address of the vb-table pointer to produce the base. // int VirtualBaseAdjustmentOffset; -// -// // The offset of the vb-table pointer within the object. Only needed for -// // incomplete types. -// int VBPtrOffset; // }; static std::pair getMSMemberPointerSlots(const MemberPointerType *MPT) { @@ -151,37 +151,17 @@ MSInheritanceAttr::Spelling Inheritance = RD->getMSInheritanceModel(); unsigned Ptrs = 0; unsigned Ints = 0; - if (MPT->isMemberFunctionPointer()) { - // Member function pointers are a struct of a function pointer followed by a - // variable number of ints depending on the inheritance model used. The - // function pointer is a real function if it is non-virtual and a vftable - // slot thunk if it is virtual. The ints select the object base passed for - // the 'this' pointer. - Ptrs = 1; // First slot is always a function pointer. - switch (Inheritance) { - case MSInheritanceAttr::Keyword_unspecified_inheritance: - ++Ints; // VBTableOffset - case MSInheritanceAttr::Keyword_virtual_inheritance: - ++Ints; // VirtualBaseAdjustmentOffset - case MSInheritanceAttr::Keyword_multiple_inheritance: - ++Ints; // NonVirtualBaseAdjustment - case MSInheritanceAttr::Keyword_single_inheritance: - break; // Nothing - } - } else { - // Data pointers are an aggregate of ints. The first int is an offset - // followed by vbtable-related offsets. - Ints = 1; // We always have a field offset. - switch (Inheritance) { - case MSInheritanceAttr::Keyword_unspecified_inheritance: - ++Ints; // VBTableOffset - case MSInheritanceAttr::Keyword_virtual_inheritance: - ++Ints; // VirtualBaseAdjustmentOffset - case MSInheritanceAttr::Keyword_multiple_inheritance: - case MSInheritanceAttr::Keyword_single_inheritance: - break; // Nothing - } - } + if (MPT->isMemberFunctionPointer()) + Ptrs = 1; + else + Ints = 1; + if (MSInheritanceAttr::hasNVOffsetField(MPT->isMemberFunctionPointer(), + Inheritance)) + Ints++; + if (MSInheritanceAttr::hasVBPtrOffsetField(Inheritance)) + Ints++; + if (MSInheritanceAttr::hasVBTableOffsetField(Inheritance)) + Ints++; return std::make_pair(Ptrs, Ints); } Index: cfe/trunk/lib/AST/MicrosoftMangle.cpp =================================================================== --- cfe/trunk/lib/AST/MicrosoftMangle.cpp +++ cfe/trunk/lib/AST/MicrosoftMangle.cpp @@ -21,6 +21,7 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/VTableBuilder.h" #include "clang/Basic/ABI.h" #include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/TargetInfo.h" @@ -121,6 +122,12 @@ void mangleDeclaration(const NamedDecl *ND); void mangleFunctionEncoding(const FunctionDecl *FD); void mangleVariableEncoding(const VarDecl *VD); + void mangleMemberDataPointer(const CXXRecordDecl *RD, const FieldDecl *FD); + void mangleMemberFunctionPointer(const CXXRecordDecl *RD, + const CXXMethodDecl *MD); + void mangleVirtualMemPtrThunk( + const CXXMethodDecl *MD, + const MicrosoftVTableContext::MethodVFTableLocation &ML); void mangleNumber(int64_t Number); void mangleType(QualType T, SourceRange Range, QualifierMangleMode QMM = QMM_Mangle); @@ -181,7 +188,6 @@ virtual bool shouldMangleCXXName(const NamedDecl *D); virtual void mangleCXXName(const NamedDecl *D, raw_ostream &Out); virtual void mangleVirtualMemPtrThunk(const CXXMethodDecl *MD, - uint64_t OffsetInVFTable, raw_ostream &); virtual void mangleThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk, @@ -371,6 +377,130 @@ } } +void MicrosoftCXXNameMangler::mangleMemberDataPointer(const CXXRecordDecl *RD, + const FieldDecl *FD) { + // ::= + // ::= $F + // ::= $G + + int64_t FO = 0; + MSInheritanceAttr::Spelling IM = RD->getMSInheritanceModel(); + if (FD) { + FO = getASTContext().getFieldOffset(FD); + assert(FO % getASTContext().getCharWidth() == 0 && + "cannot take address of bitfield"); + FO /= getASTContext().getCharWidth(); + } else if (!RD->nullFieldOffsetIsZero()) { + FO = -1; + } + + switch (IM) { + case MSInheritanceAttr::Keyword_single_inheritance: + case MSInheritanceAttr::Keyword_multiple_inheritance: { + // If we only have a single field, it's just an integer literal. + llvm::APSInt Val(64, /*isUnsigned=*/false); + Val = FO; + mangleIntegerLiteral(Val, /*IsBoolean=*/false); + break; + } + + // Otherwise, we have an aggregate, but all adjusting fields should be zero, + // because we don't allow casts (even implicit) in the context of a template + // argument. + case MSInheritanceAttr::Keyword_virtual_inheritance: + Out << "$F"; + mangleNumber(FO); + mangleNumber(0); + break; + + case MSInheritanceAttr::Keyword_unspecified_inheritance: + Out << "$G"; + mangleNumber(FO); + mangleNumber(0); + mangleNumber(0); + break; + } +} + +void +MicrosoftCXXNameMangler::mangleMemberFunctionPointer(const CXXRecordDecl *RD, + const CXXMethodDecl *MD) { + // ::= $1? + // ::= $H? + // ::= $I? + // ::= $J? + // ::= $0A@ + + MSInheritanceAttr::Spelling IM = RD->getMSInheritanceModel(); + + // The null member function pointer is $0A@ in function templates and crashes + // MSVC when used in class templates, so we don't know what they really look + // like. + if (!MD) { + Out << "$0A@"; + return; + } + + char Code = '\0'; + switch (IM) { + case MSInheritanceAttr::Keyword_single_inheritance: Code = '1'; break; + case MSInheritanceAttr::Keyword_multiple_inheritance: Code = 'H'; break; + case MSInheritanceAttr::Keyword_virtual_inheritance: Code = 'I'; break; + case MSInheritanceAttr::Keyword_unspecified_inheritance: Code = 'J'; break; + } + + Out << '$' << Code << '?'; + + // If non-virtual, mangle the name. If virtual, mangle as a virtual memptr + // thunk. + uint64_t NVOffset = 0; + uint64_t VBTableOffset = 0; + if (!MD) { + mangleNumber(0); + } else if (MD->isVirtual()) { + MicrosoftVTableContext *VTContext = + cast(getASTContext().getVTableContext()); + const MicrosoftVTableContext::MethodVFTableLocation &ML = + VTContext->getMethodVFTableLocation(GlobalDecl(MD)); + mangleVirtualMemPtrThunk(MD, ML); + NVOffset = ML.VFPtrOffset.getQuantity(); + VBTableOffset = ML.VBTableIndex * 4; + if (ML.VBase) { + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID( + DiagnosticsEngine::Error, + "cannot mangle pointers to member functions from virtual bases"); + Diags.Report(MD->getLocation(), DiagID); + } + } else { + mangleName(MD); + mangleFunctionEncoding(MD); + } + + if (MSInheritanceAttr::hasNVOffsetField(/*IsMemberFunction=*/true, IM)) + mangleNumber(NVOffset); + if (MSInheritanceAttr::hasVBPtrOffsetField(IM)) + mangleNumber(0); + if (MSInheritanceAttr::hasVBTableOffsetField(IM)) + mangleNumber(VBTableOffset); +} + +void MicrosoftCXXNameMangler::mangleVirtualMemPtrThunk( + const CXXMethodDecl *MD, + const MicrosoftVTableContext::MethodVFTableLocation &ML) { + // Get the vftable offset. + CharUnits PointerWidth = getASTContext().toCharUnitsFromBits( + getASTContext().getTargetInfo().getPointerWidth(0)); + uint64_t OffsetInVFTable = ML.Index * PointerWidth.getQuantity(); + + Out << "?_9"; + mangleName(MD->getParent()); + Out << "$B"; + mangleNumber(OffsetInVFTable); + Out << 'A'; + Out << (PointersAre64Bit ? 'A' : 'E'); +} + void MicrosoftCXXNameMangler::mangleName(const NamedDecl *ND) { // ::= {[]+ | []}? @ const DeclContext *DC = ND->getDeclContext(); @@ -928,7 +1058,7 @@ void MicrosoftCXXNameMangler::mangleTemplateArgs(const TemplateDecl *TD, const TemplateArgumentList &TemplateArgs) { - // ::= { | }+ @ + // ::= + @ unsigned NumTemplateArgs = TemplateArgs.size(); for (unsigned i = 0; i < NumTemplateArgs; ++i) { const TemplateArgument &TA = TemplateArgs[i]; @@ -939,6 +1069,15 @@ void MicrosoftCXXNameMangler::mangleTemplateArg(const TemplateDecl *TD, const TemplateArgument &TA) { + // ::= + // ::= + // ::= + // ::= + // ::= $E? + // ::= $1? + // ::= $0A@ + // ::= + switch (TA.getKind()) { case TemplateArgument::Null: llvm_unreachable("Can't mangle null template arguments!"); @@ -951,16 +1090,31 @@ } case TemplateArgument::Declaration: { const NamedDecl *ND = cast(TA.getAsDecl()); - mangle(ND, TA.isDeclForReferenceParam() ? "$E?" : "$1?"); + if (const FieldDecl *FD = dyn_cast(ND)) + mangleMemberDataPointer(cast(FD->getParent()), FD); + else if (const CXXMethodDecl *MD = dyn_cast(ND)) + mangleMemberFunctionPointer(MD->getParent(), MD); + else + mangle(ND, TA.isDeclForReferenceParam() ? "$E?" : "$1?"); break; } case TemplateArgument::Integral: mangleIntegerLiteral(TA.getAsIntegral(), TA.getIntegralType()->isBooleanType()); break; - case TemplateArgument::NullPtr: - Out << "$0A@"; + case TemplateArgument::NullPtr: { + QualType T = TA.getNullPtrType(); + if (const MemberPointerType *MPT = T->getAs()) { + const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl(); + if (MPT->isMemberFunctionPointerType()) + mangleMemberFunctionPointer(RD, 0); + else + mangleMemberDataPointer(RD, 0); + } else { + Out << "$0A@"; + } break; + } case TemplateArgument::Expression: mangleExpression(TA.getAsExpr()); break; @@ -1924,17 +2078,17 @@ } } -void MicrosoftMangleContextImpl::mangleVirtualMemPtrThunk( - const CXXMethodDecl *MD, uint64_t OffsetInVFTable, raw_ostream &Out) { - bool Is64Bit = getASTContext().getTargetInfo().getPointerWidth(0) == 64; +void +MicrosoftMangleContextImpl::mangleVirtualMemPtrThunk(const CXXMethodDecl *MD, + raw_ostream &Out) { + MicrosoftVTableContext *VTContext = + cast(getASTContext().getVTableContext()); + const MicrosoftVTableContext::MethodVFTableLocation &ML = + VTContext->getMethodVFTableLocation(GlobalDecl(MD)); MicrosoftCXXNameMangler Mangler(*this, Out); - Mangler.getStream() << "\01??_9"; - Mangler.mangleName(MD->getParent()); - Mangler.getStream() << "$B"; - Mangler.mangleNumber(OffsetInVFTable); - Mangler.getStream() << "A"; - Mangler.getStream() << (Is64Bit ? "A" : "E"); + Mangler.getStream() << "\01?"; + Mangler.mangleVirtualMemPtrThunk(MD, ML); } void MicrosoftMangleContextImpl::mangleThunk(const CXXMethodDecl *MD, Index: cfe/trunk/lib/CodeGen/CGVTables.h =================================================================== --- cfe/trunk/lib/CodeGen/CGVTables.h +++ cfe/trunk/lib/CodeGen/CGVTables.h @@ -31,9 +31,8 @@ class CodeGenVTables { CodeGenModule &CGM; - // FIXME: Consider moving VTContext into respective CXXABI classes? - OwningPtr VTContext; - + VTableContextBase *VTContext; + /// VTableAddressPointsMapTy - Address points for a single vtable. typedef llvm::DenseMap VTableAddressPointsMapTy; @@ -71,11 +70,11 @@ CodeGenVTables(CodeGenModule &CGM); ItaniumVTableContext &getItaniumVTableContext() { - return *cast(VTContext.get()); + return *cast(VTContext); } MicrosoftVTableContext &getMicrosoftVTableContext() { - return *cast(VTContext.get()); + return *cast(VTContext); } /// getSubVTTIndex - Return the index of the sub-VTT for the base class of the Index: cfe/trunk/lib/CodeGen/CGVTables.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CGVTables.cpp +++ cfe/trunk/lib/CodeGen/CGVTables.cpp @@ -29,12 +29,8 @@ using namespace clang; using namespace CodeGen; -CodeGenVTables::CodeGenVTables(CodeGenModule &CGM) : CGM(CGM) { - if (CGM.getTarget().getCXXABI().isMicrosoft()) - VTContext.reset(new MicrosoftVTableContext(CGM.getContext())); - else - VTContext.reset(new ItaniumVTableContext(CGM.getContext())); -} +CodeGenVTables::CodeGenVTables(CodeGenModule &CGM) + : CGM(CGM), VTContext(CGM.getContext().getVTableContext()) {} llvm::Constant *CodeGenModule::GetAddrOfThunk(GlobalDecl GD, const ThunkInfo &Thunk) { Index: cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp =================================================================== --- cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp +++ cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp @@ -1327,44 +1327,6 @@ CGF.EmitBlock(EndBlock); } -// Member pointer helpers. -static bool hasVBPtrOffsetField(MSInheritanceAttr::Spelling Inheritance) { - return Inheritance == MSInheritanceAttr::Keyword_unspecified_inheritance; -} - -static bool hasOnlyOneField(bool IsMemberFunction, - MSInheritanceAttr::Spelling Inheritance) { - if (IsMemberFunction) - return Inheritance <= MSInheritanceAttr::Keyword_single_inheritance; - return Inheritance <= MSInheritanceAttr::Keyword_multiple_inheritance; -} - -// Only member pointers to functions need a this adjustment, since it can be -// combined with the field offset for data pointers. -static bool -hasNonVirtualBaseAdjustmentField(bool IsMemberFunction, - MSInheritanceAttr::Spelling Inheritance) { - return IsMemberFunction && - Inheritance >= MSInheritanceAttr::Keyword_multiple_inheritance; -} - -static bool -hasVirtualBaseAdjustmentField(MSInheritanceAttr::Spelling Inheritance) { - return Inheritance >= MSInheritanceAttr::Keyword_virtual_inheritance; -} - -// Use zero for the field offset of a null data member pointer if we can -// guarantee that zero is not a valid field offset, or if the member pointer has -// multiple fields. Polymorphic classes have a vfptr at offset zero, so we can -// use zero for null. If there are multiple fields, we can use zero even if it -// is a valid field offset because null-ness testing will check the other -// fields. -static bool nullFieldOffsetIsZero(const CXXRecordDecl *RD) { - return RD->getMSInheritanceModel() >= - MSInheritanceAttr::Keyword_virtual_inheritance || - (RD->hasDefinition() && RD->isPolymorphic()); -} - bool MicrosoftCXXABI::isZeroInitializable(const MemberPointerType *MPT) { // Null-ness for function memptrs only depends on the first field, which is // the function pointer. The rest don't matter, so we can zero initialize. @@ -1376,8 +1338,8 @@ // valid field offset. const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl(); MSInheritanceAttr::Spelling Inheritance = RD->getMSInheritanceModel(); - return (!hasVirtualBaseAdjustmentField(Inheritance) && - nullFieldOffsetIsZero(RD)); + return (!MSInheritanceAttr::hasVBTableOffsetField(Inheritance) && + RD->nullFieldOffsetIsZero()); } llvm::Type * @@ -1390,12 +1352,12 @@ else fields.push_back(CGM.IntTy); // FieldOffset - if (hasNonVirtualBaseAdjustmentField(MPT->isMemberFunctionPointer(), - Inheritance)) + if (MSInheritanceAttr::hasNVOffsetField(MPT->isMemberFunctionPointer(), + Inheritance)) fields.push_back(CGM.IntTy); - if (hasVBPtrOffsetField(Inheritance)) + if (MSInheritanceAttr::hasVBPtrOffsetField(Inheritance)) fields.push_back(CGM.IntTy); - if (hasVirtualBaseAdjustmentField(Inheritance)) + if (MSInheritanceAttr::hasVBTableOffsetField(Inheritance)) fields.push_back(CGM.IntTy); // VirtualBaseAdjustmentOffset if (fields.size() == 1) @@ -1413,18 +1375,18 @@ // FunctionPointerOrVirtualThunk fields.push_back(llvm::Constant::getNullValue(CGM.VoidPtrTy)); } else { - if (nullFieldOffsetIsZero(RD)) + if (RD->nullFieldOffsetIsZero()) fields.push_back(getZeroInt()); // FieldOffset else fields.push_back(getAllOnesInt()); // FieldOffset } - if (hasNonVirtualBaseAdjustmentField(MPT->isMemberFunctionPointer(), - Inheritance)) + if (MSInheritanceAttr::hasNVOffsetField(MPT->isMemberFunctionPointer(), + Inheritance)) fields.push_back(getZeroInt()); - if (hasVBPtrOffsetField(Inheritance)) + if (MSInheritanceAttr::hasVBPtrOffsetField(Inheritance)) fields.push_back(getZeroInt()); - if (hasVirtualBaseAdjustmentField(Inheritance)) + if (MSInheritanceAttr::hasVBTableOffsetField(Inheritance)) fields.push_back(getAllOnesInt()); } @@ -1449,17 +1411,17 @@ // Single inheritance class member pointer are represented as scalars instead // of aggregates. - if (hasOnlyOneField(IsMemberFunction, Inheritance)) + if (MSInheritanceAttr::hasOnlyOneField(IsMemberFunction, Inheritance)) return FirstField; llvm::SmallVector fields; fields.push_back(FirstField); - if (hasNonVirtualBaseAdjustmentField(IsMemberFunction, Inheritance)) + if (MSInheritanceAttr::hasNVOffsetField(IsMemberFunction, Inheritance)) fields.push_back(llvm::ConstantInt::get( CGM.IntTy, NonVirtualBaseAdjustment.getQuantity())); - if (hasVBPtrOffsetField(Inheritance)) { + if (MSInheritanceAttr::hasVBPtrOffsetField(Inheritance)) { CharUnits Offs = CharUnits::Zero(); if (RD->getNumVBases()) Offs = getContext().getASTRecordLayout(RD).getVBPtrOffset(); @@ -1467,7 +1429,7 @@ } // The rest of the fields are adjusted by conversions to a more derived class. - if (hasVirtualBaseAdjustmentField(Inheritance)) + if (MSInheritanceAttr::hasVBTableOffsetField(Inheritance)) fields.push_back(getZeroInt()); return llvm::ConstantStruct::getAnon(fields); @@ -1552,7 +1514,7 @@ getContext().getTargetInfo().getPointerWidth(0)); uint64_t OffsetInVFTable = ML.Index * PointerWidth.getQuantity(); llvm::raw_svector_ostream Out(ThunkName); - getMangleContext().mangleVirtualMemPtrThunk(MD, OffsetInVFTable, Out); + getMangleContext().mangleVirtualMemPtrThunk(MD, Out); Out.flush(); llvm::Function *Thunk = EmitVirtualMemPtrThunk(MD, ThunkName.str()); @@ -1593,7 +1555,8 @@ // single icmp. const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl(); MSInheritanceAttr::Spelling Inheritance = RD->getMSInheritanceModel(); - if (hasOnlyOneField(MPT->isMemberFunctionPointer(), Inheritance)) + if (MSInheritanceAttr::hasOnlyOneField(MPT->isMemberFunctionPointer(), + Inheritance)) return Builder.CreateICmp(Eq, L, R); // Compare the first field. @@ -1785,9 +1748,9 @@ // We need to extract values. unsigned I = 0; FieldOffset = Builder.CreateExtractValue(MemPtr, I++); - if (hasVBPtrOffsetField(Inheritance)) + if (MSInheritanceAttr::hasVBPtrOffsetField(Inheritance)) VBPtrOffset = Builder.CreateExtractValue(MemPtr, I++); - if (hasVirtualBaseAdjustmentField(Inheritance)) + if (MSInheritanceAttr::hasVBTableOffsetField(Inheritance)) VirtualBaseAdjustmentOffset = Builder.CreateExtractValue(MemPtr, I++); } @@ -1840,7 +1803,7 @@ CXXRecordDecl *SrcRD = SrcTy->getMostRecentCXXRecordDecl(); CXXRecordDecl *DstRD = DstTy->getMostRecentCXXRecordDecl(); if (IsReinterpret && - nullFieldOffsetIsZero(SrcRD) == nullFieldOffsetIsZero(DstRD)) + SrcRD->nullFieldOffsetIsZero() == DstRD->nullFieldOffsetIsZero()) return Src; CGBuilderTy &Builder = CGF.Builder; @@ -1870,15 +1833,15 @@ llvm::Value *VirtualBaseAdjustmentOffset = 0; llvm::Value *VBPtrOffset = 0; MSInheritanceAttr::Spelling SrcInheritance = SrcRD->getMSInheritanceModel(); - if (!hasOnlyOneField(IsFunc, SrcInheritance)) { + if (!MSInheritanceAttr::hasOnlyOneField(IsFunc, SrcInheritance)) { // We need to extract values. unsigned I = 0; FirstField = Builder.CreateExtractValue(Src, I++); - if (hasNonVirtualBaseAdjustmentField(IsFunc, SrcInheritance)) + if (MSInheritanceAttr::hasNVOffsetField(IsFunc, SrcInheritance)) NonVirtualBaseAdjustment = Builder.CreateExtractValue(Src, I++); - if (hasVBPtrOffsetField(SrcInheritance)) + if (MSInheritanceAttr::hasVBPtrOffsetField(SrcInheritance)) VBPtrOffset = Builder.CreateExtractValue(Src, I++); - if (hasVirtualBaseAdjustmentField(SrcInheritance)) + if (MSInheritanceAttr::hasVBTableOffsetField(SrcInheritance)) VirtualBaseAdjustmentOffset = Builder.CreateExtractValue(Src, I++); } @@ -1902,19 +1865,19 @@ // Recompose dst from the null struct and the adjusted fields from src. MSInheritanceAttr::Spelling DstInheritance = DstRD->getMSInheritanceModel(); llvm::Value *Dst; - if (hasOnlyOneField(IsFunc, DstInheritance)) { + if (MSInheritanceAttr::hasOnlyOneField(IsFunc, DstInheritance)) { Dst = FirstField; } else { Dst = llvm::UndefValue::get(DstNull->getType()); unsigned Idx = 0; Dst = Builder.CreateInsertValue(Dst, FirstField, Idx++); - if (hasNonVirtualBaseAdjustmentField(IsFunc, DstInheritance)) + if (MSInheritanceAttr::hasNVOffsetField(IsFunc, DstInheritance)) Dst = Builder.CreateInsertValue( Dst, getValueOrZeroInt(NonVirtualBaseAdjustment), Idx++); - if (hasVBPtrOffsetField(DstInheritance)) + if (MSInheritanceAttr::hasVBPtrOffsetField(DstInheritance)) Dst = Builder.CreateInsertValue( Dst, getValueOrZeroInt(VBPtrOffset), Idx++); - if (hasVirtualBaseAdjustmentField(DstInheritance)) + if (MSInheritanceAttr::hasVBTableOffsetField(DstInheritance)) Dst = Builder.CreateInsertValue( Dst, getValueOrZeroInt(VirtualBaseAdjustmentOffset), Idx++); } @@ -1955,15 +1918,15 @@ llvm::Constant *VirtualBaseAdjustmentOffset = 0; llvm::Constant *VBPtrOffset = 0; bool IsFunc = SrcTy->isMemberFunctionPointer(); - if (!hasOnlyOneField(IsFunc, SrcInheritance)) { + if (!MSInheritanceAttr::hasOnlyOneField(IsFunc, SrcInheritance)) { // We need to extract values. unsigned I = 0; FirstField = Src->getAggregateElement(I++); - if (hasNonVirtualBaseAdjustmentField(IsFunc, SrcInheritance)) + if (MSInheritanceAttr::hasNVOffsetField(IsFunc, SrcInheritance)) NonVirtualBaseAdjustment = Src->getAggregateElement(I++); - if (hasVBPtrOffsetField(SrcInheritance)) + if (MSInheritanceAttr::hasVBPtrOffsetField(SrcInheritance)) VBPtrOffset = Src->getAggregateElement(I++); - if (hasVirtualBaseAdjustmentField(SrcInheritance)) + if (MSInheritanceAttr::hasVBTableOffsetField(SrcInheritance)) VirtualBaseAdjustmentOffset = Src->getAggregateElement(I++); } @@ -1986,16 +1949,16 @@ // FIXME PR15713: Support conversions through virtually derived classes. // Recompose dst from the null struct and the adjusted fields from src. - if (hasOnlyOneField(IsFunc, DstInheritance)) + if (MSInheritanceAttr::hasOnlyOneField(IsFunc, DstInheritance)) return FirstField; llvm::SmallVector Fields; Fields.push_back(FirstField); - if (hasNonVirtualBaseAdjustmentField(IsFunc, DstInheritance)) + if (MSInheritanceAttr::hasNVOffsetField(IsFunc, DstInheritance)) Fields.push_back(getConstantOrZeroInt(NonVirtualBaseAdjustment)); - if (hasVBPtrOffsetField(DstInheritance)) + if (MSInheritanceAttr::hasVBPtrOffsetField(DstInheritance)) Fields.push_back(getConstantOrZeroInt(VBPtrOffset)); - if (hasVirtualBaseAdjustmentField(DstInheritance)) + if (MSInheritanceAttr::hasVBTableOffsetField(DstInheritance)) Fields.push_back(getConstantOrZeroInt(VirtualBaseAdjustmentOffset)); return llvm::ConstantStruct::getAnon(Fields); } @@ -2026,11 +1989,11 @@ // We need to extract values. unsigned I = 0; FunctionPointer = Builder.CreateExtractValue(MemPtr, I++); - if (hasNonVirtualBaseAdjustmentField(MPT, Inheritance)) + if (MSInheritanceAttr::hasNVOffsetField(MPT, Inheritance)) NonVirtualBaseAdjustment = Builder.CreateExtractValue(MemPtr, I++); - if (hasVBPtrOffsetField(Inheritance)) + if (MSInheritanceAttr::hasVBPtrOffsetField(Inheritance)) VBPtrOffset = Builder.CreateExtractValue(MemPtr, I++); - if (hasVirtualBaseAdjustmentField(Inheritance)) + if (MSInheritanceAttr::hasVBTableOffsetField(Inheritance)) VirtualBaseAdjustmentOffset = Builder.CreateExtractValue(MemPtr, I++); } Index: cfe/trunk/test/CodeGenCXX/mangle-ms-templates-memptrs.cpp =================================================================== --- cfe/trunk/test/CodeGenCXX/mangle-ms-templates-memptrs.cpp +++ cfe/trunk/test/CodeGenCXX/mangle-ms-templates-memptrs.cpp @@ -0,0 +1,128 @@ +// RUN: %clang_cc1 -Wno-microsoft -fno-rtti -std=c++11 -emit-llvm %s -o - -triple=i386-pc-win32 | FileCheck %s + +struct U; +static_assert(sizeof(void (U::*)()) == 2 * sizeof(void*) + 2 * sizeof(int), ""); + +struct A { int a; }; +struct B { int b; }; + +struct S { int a, b; void f(); virtual void g(); }; +struct M : A, B { int a, b; void f(); virtual void g(); }; +struct V : virtual A { int a, b; void f(); virtual void g(); }; +struct U { int a, b; void f(); virtual void g(); }; + +struct C { virtual void f(); }; +struct D { virtual void g(); }; +struct O : C, D { virtual void g(); }; // override of non-primary + +// Test data member pointers. +template +int ReadField(T &o) { + return F ? o.*F : 0; +} + +void ReadFields() { + A a; + S s; + M m; + V v; + U u; + ReadField(s); + ReadField(m); + ReadField(v); + ReadField(u); + ReadField(s); + ReadField(m); + ReadField(v); + ReadField(u); + ReadField(s); + ReadField(m); + ReadField(v); + ReadField(u); + + // Non-polymorphic null data memptr vs first field memptr. + ReadField(a); + ReadField(a); +} + +// CHECK-LABEL: define {{.*}}ReadFields +// CHECK: call {{.*}} @"\01??$ReadField@US@@$03@@YAHAAUS@@@Z" +// CHECK: call {{.*}} @"\01??$ReadField@UM@@$0M@@@YAHAAUM@@@Z" +// CHECK: call {{.*}} @"\01??$ReadField@UV@@$F7A@@@YAHAAUV@@@Z" +// CHECK: call {{.*}} @"\01??$ReadField@UU@@$G3A@A@@@YAHAAUU@@@Z" +// CHECK: call {{.*}} @"\01??$ReadField@US@@$07@@YAHAAUS@@@Z" +// CHECK: call {{.*}} @"\01??$ReadField@UM@@$0BA@@@YAHAAUM@@@Z" +// CHECK: call {{.*}} @"\01??$ReadField@UV@@$FM@A@@@YAHAAUV@@@Z" +// CHECK: call {{.*}} @"\01??$ReadField@UU@@$G7A@A@@@YAHAAUU@@@Z" + +// MSVC mangles null member pointers in function templates wrong, but it gets +// them right in class templates. +// CHECK: call {{.*}} @"\01??$ReadField@US@@$0A@@@YAHAAUS@@@Z" +// CHECK: call {{.*}} @"\01??$ReadField@UM@@$0A@@@YAHAAUM@@@Z" +// CHECK: call {{.*}} @"\01??$ReadField@UV@@$FA@A@@@YAHAAUV@@@Z" +// CHECK: call {{.*}} @"\01??$ReadField@UU@@$GA@A@A@@@YAHAAUU@@@Z" + +// Non-polymorphic null data memptr vs first field memptr. MSVC mangles these +// the same. +// CHECK: call {{.*}} @"\01??$ReadField@UA@@$0A@@@YAHAAUA@@@Z" +// CHECK: call {{.*}} @"\01??$ReadField@UA@@$0?0@@YAHAAUA@@@Z" + +// Test member function pointers. +template +void CallMethod(T &o) { + (o.*MFP)(); +} + +void CallMethods() { + S s; + M m; + V v; + U u; + O o; + + // Non-virtual methods. + CallMethod(s); + CallMethod(m); + CallMethod(v); + CallMethod(u); + + // Virtual methods requiring thunk mangling. + CallMethod(s); + CallMethod(m); + CallMethod(v); + CallMethod(u); + + // A member pointer for a non-primary vbase will have a non-zero this + // adjustment. + CallMethod(o); + + // Null member pointers. + CallMethod(s); + CallMethod(m); + CallMethod(v); + CallMethod(u); +} + +// CHECK-LABEL: define {{.*}}CallMethods +// CHECK: call {{.*}} @"\01??$CallMethod@US@@$1?f@1@QAEXXZ@@YAXAAUS@@@Z" +// CHECK: call {{.*}} @"\01??$CallMethod@UM@@$H?f@1@QAEXXZA@@@YAXAAUM@@@Z" +// CHECK: call {{.*}} @"\01??$CallMethod@UV@@$I?f@1@QAEXXZA@A@@@YAXAAUV@@@Z" +// CHECK: call {{.*}} @"\01??$CallMethod@UU@@$J?f@1@QAEXXZA@A@A@@@YAXAAUU@@@Z" + +// PR17034: MSVC reuses the same thunk for every virtual g method because they +// are all at vftable offset zero. They then mangle the name of the first thunk +// created into the name of the template instantiation, which is definitely a +// bug. We don't follow them here. Instead of ?_91@ backref below, they would +// get ?_9S@@ in every instantiation after the first. + +// CHECK: call {{.*}} @"\01??$CallMethod@US@@$1??_91@$BA@AE@@YAXAAUS@@@Z" +// CHECK: call {{.*}} @"\01??$CallMethod@UM@@$H??_91@$BA@AEA@@@YAXAAUM@@@Z" +// CHECK: call {{.*}} @"\01??$CallMethod@UV@@$I??_91@$BA@AEA@A@@@YAXAAUV@@@Z" +// CHECK: call {{.*}} @"\01??$CallMethod@UU@@$J??_91@$BA@AEA@A@A@@@YAXAAUU@@@Z" + +// CHECK: call {{.*}} @"\01??$CallMethod@UO@@$H??_91@$BA@AE3@@YAXAAUO@@@Z" + +// CHECK: call {{.*}} @"\01??$CallMethod@US@@$0A@@@YAXAAUS@@@Z" +// CHECK: call {{.*}} @"\01??$CallMethod@UM@@$0A@@@YAXAAUM@@@Z" +// CHECK: call {{.*}} @"\01??$CallMethod@UV@@$0A@@@YAXAAUV@@@Z" +// CHECK: call {{.*}} @"\01??$CallMethod@UU@@$0A@@@YAXAAUU@@@Z"