Index: include/clang/AST/ASTContext.h =================================================================== --- include/clang/AST/ASTContext.h +++ 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: include/clang/AST/Mangle.h =================================================================== --- include/clang/AST/Mangle.h +++ include/clang/AST/Mangle.h @@ -182,7 +182,7 @@ class MicrosoftMangleContext : public MangleContext { public: - explicit MicrosoftMangleContext(ASTContext &C, DiagnosticsEngine &D) + MicrosoftMangleContext(ASTContext &C, DiagnosticsEngine &D) : MangleContext(C, D, MK_Microsoft) {} /// \brief Mangle vftable symbols. Only a subset of the bases along the path @@ -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: include/clang/Basic/Attr.td =================================================================== --- include/clang/Basic/Attr.td +++ 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: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -3095,6 +3095,9 @@ def ext_ms_deref_template_argument: ExtWarn< "non-type template argument containing a dereference operation is a " "Microsoft extension">, InGroup; +def ext_ms_null_memptr_template_arg: ExtWarn< + "template instantiation with a null pointer to data member is unstable in " + "the Microsoft C++ ABI">, InGroup; // C++ template specialization def err_template_spec_unknown_kind : Error< Index: lib/AST/ASTContext.cpp =================================================================== --- lib/AST/ASTContext.cpp +++ 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: lib/AST/MicrosoftCXXABI.cpp =================================================================== --- lib/AST/MicrosoftCXXABI.cpp +++ 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: lib/AST/MicrosoftMangle.cpp =================================================================== --- lib/AST/MicrosoftMangle.cpp +++ 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,11 @@ void mangleDeclaration(const NamedDecl *ND); void mangleFunctionEncoding(const FunctionDecl *FD); void mangleVariableEncoding(const VarDecl *VD); + void mangleMemberDataPointer(const FieldDecl *FD); + void mangleMemberFunctionPointer(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 +187,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 +376,114 @@ } } +void MicrosoftCXXNameMangler::mangleMemberDataPointer(const FieldDecl *FD) { + // ::= + // ::= $F + // ::= $G + + const CXXRecordDecl *RD = cast(FD->getParent()); + MSInheritanceAttr::Spelling IM = RD->getMSInheritanceModel(); + uint64_t FO = getASTContext().getFieldOffset(FD); + assert(FO % getASTContext().getCharWidth() == 0 && + "cannot take address of bitfield"); + FO /= getASTContext().getCharWidth(); + + 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=*/true); + 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 CXXMethodDecl *MD) { + // ::= $1? + // ::= $H? + // ::= $I? + // ::= $J? + + const CXXRecordDecl *RD = cast(MD->getParent()); + MSInheritanceAttr::Spelling IM = RD->getMSInheritanceModel(); + + 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->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 +1041,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 +1052,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,7 +1073,12 @@ } case TemplateArgument::Declaration: { const NamedDecl *ND = cast(TA.getAsDecl()); - mangle(ND, TA.isDeclForReferenceParam() ? "$E?" : "$1?"); + if (const FieldDecl *FD = dyn_cast(ND)) + mangleMemberDataPointer(FD); + else if (const CXXMethodDecl *MD = dyn_cast(ND)) + mangleMemberFunctionPointer(MD); + else + mangle(ND, TA.isDeclForReferenceParam() ? "$E?" : "$1?"); break; } case TemplateArgument::Integral: @@ -959,6 +1086,9 @@ TA.getIntegralType()->isBooleanType()); break; case TemplateArgument::NullPtr: + // Amusingly, this collides with the mangling for a pointer to the first + // data member of a standard layout class. Sema should have already issued + // a -Wmicrosoft warning for this. Out << "$0A@"; break; case TemplateArgument::Expression: @@ -1924,17 +2054,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: lib/CodeGen/CGCXXABI.h =================================================================== --- lib/CodeGen/CGCXXABI.h +++ lib/CodeGen/CGCXXABI.h @@ -43,8 +43,8 @@ CodeGenModule &CGM; OwningPtr MangleCtx; - CGCXXABI(CodeGenModule &CGM) - : CGM(CGM), MangleCtx(CGM.getContext().createMangleContext()) {} + CGCXXABI(CodeGenModule &CGM, MangleContext *MangleCtx) + : CGM(CGM), MangleCtx(MangleCtx) {} protected: ImplicitParamDecl *&getThisDecl(CodeGenFunction &CGF) { Index: lib/CodeGen/CGVTables.h =================================================================== --- lib/CodeGen/CGVTables.h +++ 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: lib/CodeGen/CGVTables.cpp =================================================================== --- lib/CodeGen/CGVTables.cpp +++ 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: lib/CodeGen/ItaniumCXXABI.cpp =================================================================== --- lib/CodeGen/ItaniumCXXABI.cpp +++ lib/CodeGen/ItaniumCXXABI.cpp @@ -46,11 +46,11 @@ } public: - ItaniumCXXABI(CodeGen::CodeGenModule &CGM, - bool UseARMMethodPtrABI = false, - bool UseARMGuardVarABI = false) : - CGCXXABI(CGM), UseARMMethodPtrABI(UseARMMethodPtrABI), - UseARMGuardVarABI(UseARMGuardVarABI) { } + ItaniumCXXABI(CodeGen::CodeGenModule &CGM, bool UseARMMethodPtrABI = false, + bool UseARMGuardVarABI = false) + : CGCXXABI(CGM, CGM.getContext().createMangleContext()), + UseARMMethodPtrABI(UseARMMethodPtrABI), + UseARMGuardVarABI(UseARMGuardVarABI) {} bool isReturnTypeIndirect(const CXXRecordDecl *RD) const { // Structures with either a non-trivial destructor or a non-trivial Index: lib/CodeGen/MicrosoftCXXABI.cpp =================================================================== --- lib/CodeGen/MicrosoftCXXABI.cpp +++ lib/CodeGen/MicrosoftCXXABI.cpp @@ -35,7 +35,8 @@ class MicrosoftCXXABI : public CGCXXABI { public: - MicrosoftCXXABI(CodeGenModule &CGM) : CGCXXABI(CGM) {} + MicrosoftCXXABI(CodeGenModule &CGM) + : CGCXXABI(CGM, CGM.getContext().createMangleContext()) {} bool HasThisReturn(GlobalDecl GD) const; @@ -1327,32 +1328,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 @@ -1376,7 +1351,7 @@ // valid field offset. const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl(); MSInheritanceAttr::Spelling Inheritance = RD->getMSInheritanceModel(); - return (!hasVirtualBaseAdjustmentField(Inheritance) && + return (!MSInheritanceAttr::hasVBTableOffsetField(Inheritance) && nullFieldOffsetIsZero(RD)); } @@ -1390,12 +1365,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) @@ -1419,12 +1394,12 @@ 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 +1424,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 +1442,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 +1527,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 +1568,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 +1761,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++); } @@ -1870,15 +1846,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 +1878,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 +1931,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 +1962,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 +2002,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: lib/Sema/SemaTemplate.cpp =================================================================== --- lib/Sema/SemaTemplate.cpp +++ lib/Sema/SemaTemplate.cpp @@ -20,6 +20,7 @@ #include "clang/AST/TypeVisitor.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/PartialDiagnostic.h" +#include "clang/Basic/TargetInfo.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/ParsedTemplate.h" @@ -4528,6 +4529,19 @@ return true; case NPV_NullPointer: S.Diag(Arg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null); + + if (S.getASTContext().getTargetInfo().getCXXABI().isMicrosoft() && + ParamType->isMemberDataPointerType()) { + // The mangling for null member pointers in the Microsoft ABI is very + // unstable. They get different manglings depending on the exact spelling + // of nullptr, and using 'nullptr' or '0' gives the same mangling as a + // pointer to the first data member of a standard layout class. + // Therefore, we give a -Wmicrosoft warning. + S.Diag(Arg->getLocStart(), diag::ext_ms_null_memptr_template_arg) + << Arg->getSourceRange(); + S.Diag(Param->getLocation(), diag::note_template_param_here); + } + Converted = TemplateArgument(ParamType, /*isNullPtr*/true); return false; case NPV_NotNullPointer: Index: test/CodeGenCXX/mangle-ms-templates-memptrs.cpp =================================================================== --- /dev/null +++ test/CodeGenCXX/mangle-ms-templates-memptrs.cpp @@ -0,0 +1,125 @@ +// RUN: %clang_cc1 -Wno-microsoft -fno-rtti -std=c++11 -emit-llvm %s -o - -fms-extensions -fdelayed-template-parsing -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); + + // Demonstration of buggy non-polymorphic null memptr behavior. + 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" +// CHECK: call {{.*}} @"\01??$ReadField@US@@$0A@@@YAHAAUS@@@Z" +// CHECK: call {{.*}} @"\01??$ReadField@UM@@$0A@@@YAHAAUM@@@Z" +// CHECK: call {{.*}} @"\01??$ReadField@UV@@$0A@@@YAHAAUV@@@Z" +// CHECK: call {{.*}} @"\01??$ReadField@UU@@$0A@@@YAHAAUU@@@Z" + + // Demonstration of buggy non-polymorphic null memptr behavior. +// CHECK: call {{.*}} @"\01??$ReadField@UA@@$0A@@@YAHAAUA@@@Z" +// CHECK: call {{.*}} @"\01??$ReadField@UA@@$0A@@@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" Index: test/SemaCXX/cxx98-compat.cpp =================================================================== --- test/SemaCXX/cxx98-compat.cpp +++ test/SemaCXX/cxx98-compat.cpp @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wc++98-compat -verify %s -// RUN: %clang_cc1 -fsyntax-only -std=c++1y -Wc++98-compat -verify %s -DCXX1YCOMPAT +// RUN: %clang_cc1 -Wno-microsoft -fsyntax-only -std=c++11 -Wc++98-compat -verify %s +// RUN: %clang_cc1 -Wno-microsoft -fsyntax-only -std=c++1y -Wc++98-compat -verify %s -DCXX1YCOMPAT namespace std { struct type_info; Index: test/SemaCXX/nullptr.cpp =================================================================== --- test/SemaCXX/nullptr.cpp +++ test/SemaCXX/nullptr.cpp @@ -1,4 +1,6 @@ -// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify -std=c++11 -ffreestanding %s +// RUN: %clang_cc1 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -fsyntax-only -verify -std=c++11 -ffreestanding %s +// RUN: %clang_cc1 -triple %ms_abi_triple -DMS_ABI -fcxx-exceptions -fexceptions -fsyntax-only -verify -std=c++11 -ffreestanding %s + #include typedef decltype(nullptr) nullptr_t; @@ -75,10 +77,22 @@ } // Template arguments can be nullptr. -template +template struct T {}; -typedef T NT; +typedef T NT; namespace test1 { template struct is_same { @@ -171,11 +185,18 @@ X x; - - template + template struct X2 {}; - - X2 x2; + + X2 x2; } namespace null_pointer_constant {