class UnresolvedSetIterator;
class UsingDecl;
class UsingShadowDecl;
+ class VTableContextBase;
namespace Builtin { class Context; }
bool isNearlyEmpty(const CXXRecordDecl *RD) const;
+ VTableContextBase *getVTableContext();
+
MangleContext *createMangleContext();
void DeepCollectObjCIvars(const ObjCInterfaceDecl *OI, bool leafClass,
void ReleaseDeclContextMaps();
llvm::OwningPtr<ParentMap> AllParents;
+
+ llvm::OwningPtr<VTableContextBase> VTContext;
};
/// \brief Utility function for constructing a nullary selector.
/// \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.
raw_ostream &Out) = 0;
virtual void mangleVirtualMemPtrThunk(const CXXMethodDecl *MD,
- uint64_t OffsetInVFTable,
raw_ostream &) = 0;
static bool classof(const MangleContext *C) {
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 {
#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"
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:
// // 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<unsigned, unsigned>
getMSMemberPointerSlots(const MemberPointerType *MPT) {
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);
}
#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"
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);
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,
}
}
+void MicrosoftCXXNameMangler::mangleMemberDataPointer(const CXXRecordDecl *RD,
+ const FieldDecl *FD) {
+ // <member-data-pointer> ::= <integer-literal>
+ // ::= $F <number> <number>
+ // ::= $G <number> <number> <number>
+
+ 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) {
+ // <member-function-pointer> ::= $1? <name>
+ // ::= $H? <name> <number>
+ // ::= $I? <name> <number> <number>
+ // ::= $J? <name> <number> <number> <number>
+ // ::= $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<MicrosoftVTableContext>(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) {
// <name> ::= <unscoped-name> {[<named-scope>]+ | [<nested-name>]}? @
const DeclContext *DC = ND->getDeclContext();
void
MicrosoftCXXNameMangler::mangleTemplateArgs(const TemplateDecl *TD,
const TemplateArgumentList &TemplateArgs) {
- // <template-args> ::= {<type> | <integer-literal>}+ @
+ // <template-args> ::= <template-arg>+ @
unsigned NumTemplateArgs = TemplateArgs.size();
for (unsigned i = 0; i < NumTemplateArgs; ++i) {
const TemplateArgument &TA = TemplateArgs[i];
void MicrosoftCXXNameMangler::mangleTemplateArg(const TemplateDecl *TD,
const TemplateArgument &TA) {
+ // <template-arg> ::= <type>
+ // ::= <integer-literal>
+ // ::= <member-data-pointer>
+ // ::= <member-function-pointer>
+ // ::= $E? <name> <type-encoding>
+ // ::= $1? <name> <type-encoding>
+ // ::= $0A@
+ // ::= <template-args>
+
switch (TA.getKind()) {
case TemplateArgument::Null:
llvm_unreachable("Can't mangle null template arguments!");
}
case TemplateArgument::Declaration: {
const NamedDecl *ND = cast<NamedDecl>(TA.getAsDecl());
- mangle(ND, TA.isDeclForReferenceParam() ? "$E?" : "$1?");
+ if (const FieldDecl *FD = dyn_cast<FieldDecl>(ND))
+ mangleMemberDataPointer(cast<CXXRecordDecl>(FD->getParent()), FD);
+ else if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(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<MemberPointerType>()) {
+ 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;
}
}
-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<MicrosoftVTableContext>(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,
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) {
class CodeGenVTables {
CodeGenModule &CGM;
- // FIXME: Consider moving VTContext into respective CXXABI classes?
- OwningPtr<VTableContextBase> VTContext;
-
+ VTableContextBase *VTContext;
+
/// VTableAddressPointsMapTy - Address points for a single vtable.
typedef llvm::DenseMap<BaseSubobject, uint64_t> VTableAddressPointsMapTy;
CodeGenVTables(CodeGenModule &CGM);
ItaniumVTableContext &getItaniumVTableContext() {
- return *cast<ItaniumVTableContext>(VTContext.get());
+ return *cast<ItaniumVTableContext>(VTContext);
}
MicrosoftVTableContext &getMicrosoftVTableContext() {
- return *cast<MicrosoftVTableContext>(VTContext.get());
+ return *cast<MicrosoftVTableContext>(VTContext);
}
/// getSubVTTIndex - Return the index of the sub-VTT for the base class of the
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.
// 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 *
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)
// 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());
}
// 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<llvm::Constant *, 4> 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();
}
// 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);
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());
// 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.
// 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++);
}
CXXRecordDecl *SrcRD = SrcTy->getMostRecentCXXRecordDecl();
CXXRecordDecl *DstRD = DstTy->getMostRecentCXXRecordDecl();
if (IsReinterpret &&
- nullFieldOffsetIsZero(SrcRD) == nullFieldOffsetIsZero(DstRD))
+ SrcRD->nullFieldOffsetIsZero() == DstRD->nullFieldOffsetIsZero())
return Src;
CGBuilderTy &Builder = CGF.Builder;
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++);
}
// 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++);
}
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++);
}
// 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<llvm::Constant *, 4> 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);
}
// 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++);
}
--- /dev/null
+// 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 <typename T, int T::*F>
+int ReadField(T &o) {
+ return F ? o.*F : 0;
+}
+
+void ReadFields() {
+ A a;
+ S s;
+ M m;
+ V v;
+ U u;
+ ReadField<S, &S::a>(s);
+ ReadField<M, &M::a>(m);
+ ReadField<V, &V::a>(v);
+ ReadField<U, &U::a>(u);
+ ReadField<S, &S::b>(s);
+ ReadField<M, &M::b>(m);
+ ReadField<V, &V::b>(v);
+ ReadField<U, &U::b>(u);
+ ReadField<S, nullptr>(s);
+ ReadField<M, nullptr>(m);
+ ReadField<V, nullptr>(v);
+ ReadField<U, nullptr>(u);
+
+ // Non-polymorphic null data memptr vs first field memptr.
+ ReadField<A, &A::a>(a);
+ ReadField<A, nullptr>(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 <typename T, void (T::*MFP)()>
+void CallMethod(T &o) {
+ (o.*MFP)();
+}
+
+void CallMethods() {
+ S s;
+ M m;
+ V v;
+ U u;
+ O o;
+
+ // Non-virtual methods.
+ CallMethod<S, &S::f>(s);
+ CallMethod<M, &M::f>(m);
+ CallMethod<V, &V::f>(v);
+ CallMethod<U, &U::f>(u);
+
+ // Virtual methods requiring thunk mangling.
+ CallMethod<S, &S::g>(s);
+ CallMethod<M, &M::g>(m);
+ CallMethod<V, &V::g>(v);
+ CallMethod<U, &U::g>(u);
+
+ // A member pointer for a non-primary vbase will have a non-zero this
+ // adjustment.
+ CallMethod<O, &O::g>(o);
+
+ // Null member pointers.
+ CallMethod<S, nullptr>(s);
+ CallMethod<M, nullptr>(m);
+ CallMethod<V, nullptr>(v);
+ CallMethod<U, nullptr>(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"