summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/lib/CodeGen/CGCall.cpp14
-rw-r--r--clang/lib/CodeGen/CodeGenTypes.h1
-rw-r--r--clang/lib/CodeGen/MicrosoftCXXABI.cpp37
-rw-r--r--clang/test/CodeGenCXX/microsoft-abi-member-pointers.cpp10
-rw-r--r--clang/test/CodeGenCXX/microsoft-abi-virtual-member-pointers.cpp134
-rw-r--r--clang/test/CodeGenCXX/microsoft-abi-vmemptr-conflicts.cpp101
-rw-r--r--clang/test/CodeGenCXX/microsoft-abi-vmemptr-fastcall.cpp11
7 files changed, 224 insertions, 84 deletions
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index aa7de709cb5..ce16d3bd64c 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -332,6 +332,20 @@ CodeGenTypes::arrangeGlobalDeclaration(GlobalDecl GD) {
return arrangeFunctionDeclaration(FD);
}
+/// Arrange a thunk that takes 'this' as the first parameter followed by
+/// varargs. Return a void pointer, regardless of the actual return type.
+/// The body of the thunk will end in a musttail call to a function of the
+/// correct type, and the caller will bitcast the function to the correct
+/// prototype.
+const CGFunctionInfo &
+CodeGenTypes::arrangeMSMemberPointerThunk(const CXXMethodDecl *MD) {
+ assert(MD->isVirtual() && "only virtual memptrs have thunks");
+ CanQual<FunctionProtoType> FTP = GetFormalType(MD);
+ CanQualType ArgTys[] = { GetThisType(Context, MD->getParent()) };
+ return arrangeLLVMFunctionInfo(Context.VoidTy, false, ArgTys,
+ FTP->getExtInfo(), RequiredArgs(1));
+}
+
/// Arrange a call as unto a free function, except possibly with an
/// additional number of formal parameters considered required.
static const CGFunctionInfo &
diff --git a/clang/lib/CodeGen/CodeGenTypes.h b/clang/lib/CodeGen/CodeGenTypes.h
index 51466c6e2c7..91727e3d5e2 100644
--- a/clang/lib/CodeGen/CodeGenTypes.h
+++ b/clang/lib/CodeGen/CodeGenTypes.h
@@ -207,6 +207,7 @@ public:
const CGFunctionInfo &arrangeCXXMethodCall(const CallArgList &args,
const FunctionProtoType *type,
RequiredArgs required);
+ const CGFunctionInfo &arrangeMSMemberPointerThunk(const CXXMethodDecl *MD);
const CGFunctionInfo &arrangeFreeFunctionType(CanQual<FunctionProtoType> Ty);
const CGFunctionInfo &arrangeFreeFunctionType(CanQual<FunctionNoProtoType> Ty);
diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
index ca1196dbbf7..9fa7f339ad3 100644
--- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -1434,6 +1434,9 @@ MicrosoftCXXABI::enumerateVBTables(const CXXRecordDecl *RD) {
llvm::Function *MicrosoftCXXABI::EmitVirtualMemPtrThunk(
const CXXMethodDecl *MD,
const MicrosoftVTableContext::MethodVFTableLocation &ML) {
+ assert(!isa<CXXConstructorDecl>(MD) && !isa<CXXDestructorDecl>(MD) &&
+ "can't form pointers to ctors or virtual dtors");
+
// Calculate the mangled name.
SmallString<256> ThunkName;
llvm::raw_svector_ostream Out(ThunkName);
@@ -1445,7 +1448,7 @@ llvm::Function *MicrosoftCXXABI::EmitVirtualMemPtrThunk(
return cast<llvm::Function>(GV);
// Create the llvm::Function.
- const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeGlobalDeclaration(MD);
+ const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeMSMemberPointerThunk(MD);
llvm::FunctionType *ThunkTy = CGM.getTypes().GetFunctionType(FnInfo);
llvm::Function *ThunkFn =
llvm::Function::Create(ThunkTy, llvm::Function::ExternalLinkage,
@@ -1464,18 +1467,28 @@ llvm::Function *MicrosoftCXXABI::EmitVirtualMemPtrThunk(
// Start codegen.
CodeGenFunction CGF(CGM);
- CGF.StartThunk(ThunkFn, MD, FnInfo);
+ CGF.CurGD = GlobalDecl(MD);
+ CGF.CurFuncIsThunk = true;
+
+ // Build FunctionArgs, but only include the implicit 'this' parameter
+ // declaration.
+ FunctionArgList FunctionArgs;
+ buildThisParam(CGF, FunctionArgs);
+
+ // Start defining the function.
+ CGF.StartFunction(GlobalDecl(), FnInfo.getReturnType(), ThunkFn, FnInfo,
+ FunctionArgs, MD->getLocation(), SourceLocation());
+ EmitThisParam(CGF);
// Load the vfptr and then callee from the vftable. The callee should have
// adjusted 'this' so that the vfptr is at offset zero.
- llvm::Value *This = CGF.LoadCXXThis();
- llvm::Value *VTable =
- CGF.GetVTablePtr(This, ThunkTy->getPointerTo()->getPointerTo());
+ llvm::Value *VTable = CGF.GetVTablePtr(
+ getThisValue(CGF), ThunkTy->getPointerTo()->getPointerTo());
llvm::Value *VFuncPtr =
CGF.Builder.CreateConstInBoundsGEP1_64(VTable, ML.Index, "vfn");
llvm::Value *Callee = CGF.Builder.CreateLoad(VFuncPtr);
- CGF.EmitCallAndReturnForThunk(Callee, 0);
+ CGF.EmitMustTailThunk(MD, getThisValue(CGF), Callee);
return ThunkFn;
}
@@ -1935,8 +1948,8 @@ MicrosoftCXXABI::BuildMemberPointer(const CXXRecordDecl *RD,
CodeGenTypes &Types = CGM.getTypes();
llvm::Constant *FirstField;
+ const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
if (!MD->isVirtual()) {
- const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
llvm::Type *Ty;
// Check whether the function has a computable LLVM signature.
if (Types.isFuncTypeConvertible(FPT)) {
@@ -1952,14 +1965,14 @@ MicrosoftCXXABI::BuildMemberPointer(const CXXRecordDecl *RD,
} else {
MicrosoftVTableContext::MethodVFTableLocation ML =
CGM.getMicrosoftVTableContext().getMethodVFTableLocation(MD);
- if (MD->isVariadic()) {
- CGM.ErrorUnsupported(MD, "pointer to variadic virtual member function");
- FirstField = llvm::Constant::getNullValue(CGM.VoidPtrTy);
- } else if (!CGM.getTypes().isFuncTypeConvertible(
- MD->getType()->castAs<FunctionType>())) {
+ if (!CGM.getTypes().isFuncTypeConvertible(
+ MD->getType()->castAs<FunctionType>())) {
CGM.ErrorUnsupported(MD, "pointer to virtual member function with "
"incomplete return or parameter type");
FirstField = llvm::Constant::getNullValue(CGM.VoidPtrTy);
+ } else if (FPT->getCallConv() == CC_X86FastCall) {
+ CGM.ErrorUnsupported(MD, "pointer to fastcall virtual member function");
+ FirstField = llvm::Constant::getNullValue(CGM.VoidPtrTy);
} else if (ML.VBase) {
CGM.ErrorUnsupported(MD, "pointer to virtual member function overriding "
"member function in virtual base class");
diff --git a/clang/test/CodeGenCXX/microsoft-abi-member-pointers.cpp b/clang/test/CodeGenCXX/microsoft-abi-member-pointers.cpp
index 80d92de3ec3..04665c93ce6 100644
--- a/clang/test/CodeGenCXX/microsoft-abi-member-pointers.cpp
+++ b/clang/test/CodeGenCXX/microsoft-abi-member-pointers.cpp
@@ -595,15 +595,15 @@ void (C::*getmp())() {
return &C::g;
}
// CHECK-LABEL: define i64 @"\01?getmp@Test4@@YAP8C@1@AEXXZXZ"()
-// CHECK: store { i8*, i32 } { i8* bitcast (void (i8*)* @"\01??_9C@Test4@@$BA@AE" to i8*), i32 4 }, { i8*, i32 }* %{{.*}}
+// CHECK: store { i8*, i32 } { i8* bitcast (void (%"struct.Test4::C"*, ...)* @"\01??_9C@Test4@@$BA@AE" to i8*), i32 4 }, { i8*, i32 }* %{{.*}}
//
-// CHECK-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C@Test4@@$BA@AE"(i8*)
+// CHECK-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C@Test4@@$BA@AE"(%"struct.Test4::C"* %this, ...)
// CHECK-NOT: getelementptr
-// CHECK: load void (i8*)*** %{{.*}}
-// CHECK: getelementptr inbounds void (i8*)** %{{.*}}, i64 0
+// CHECK: load void (%"struct.Test4::C"*, ...)*** %{{.*}}
+// CHECK: getelementptr inbounds void (%"struct.Test4::C"*, ...)** %{{.*}}, i64 0
// CHECK-NOT: getelementptr
-// CHECK: call x86_thiscallcc void %
+// CHECK: musttail call x86_thiscallcc void (%"struct.Test4::C"*, ...)* %
}
diff --git a/clang/test/CodeGenCXX/microsoft-abi-virtual-member-pointers.cpp b/clang/test/CodeGenCXX/microsoft-abi-virtual-member-pointers.cpp
index 5e645aa4823..1880f045762 100644
--- a/clang/test/CodeGenCXX/microsoft-abi-virtual-member-pointers.cpp
+++ b/clang/test/CodeGenCXX/microsoft-abi-virtual-member-pointers.cpp
@@ -49,111 +49,111 @@ void f() {
// CHECK32-LABEL: define void @"\01?f@@YAXXZ"()
-// CHECK32: store i8* bitcast (void (%struct.C*)* @"\01??_9C@@$BA@AE" to i8*), i8** %ptr
-// CHECK32: store i8* bitcast (i32 (%struct.C*, i32, double)* @"\01??_9C@@$B3AE" to i8*), i8** %ptr2
-// CHECK32: store i8* bitcast (void (%struct.C*, %struct.S*, i32)* @"\01??_9C@@$B7AE" to i8*), i8** %ptr3
-// CHECK32: store i8* bitcast (void (%"struct.(anonymous namespace)::D"*)* @"\01??_9D@?A@@$BA@AE" to i8*), i8** %ptr4
+// CHECK32: store i8* bitcast (void (%struct.C*, ...)* @"\01??_9C@@$BA@AE" to i8*), i8** %ptr
+// CHECK32: store i8* bitcast (void (%struct.C*, ...)* @"\01??_9C@@$B3AE" to i8*), i8** %ptr2
+// CHECK32: store i8* bitcast (void (%struct.C*, ...)* @"\01??_9C@@$B7AE" to i8*), i8** %ptr3
+// CHECK32: store i8* bitcast (void (%"struct.(anonymous namespace)::D"*, ...)* @"\01??_9D@?A@@$BA@AE" to i8*), i8** %ptr4
// CHECK32: }
//
// CHECK64-LABEL: define void @"\01?f@@YAXXZ"()
-// CHECK64: store i8* bitcast (void (%struct.C*)* @"\01??_9C@@$BA@AA" to i8*), i8** %ptr
-// CHECK64: store i8* bitcast (i32 (%struct.C*, i32, double)* @"\01??_9C@@$B7AA" to i8*), i8** %ptr2
-// CHECK64: store i8* bitcast (void (%struct.C*, %struct.S*, i32)* @"\01??_9C@@$BBA@AA" to i8*), i8** %ptr3
-// CHECK64: store i8* bitcast (void (%"struct.(anonymous namespace)::D"*)* @"\01??_9D@?A@@$BA@AA" to i8*), i8** %ptr
+// CHECK64: store i8* bitcast (void (%struct.C*, ...)* @"\01??_9C@@$BA@AA" to i8*), i8** %ptr
+// CHECK64: store i8* bitcast (void (%struct.C*, ...)* @"\01??_9C@@$B7AA" to i8*), i8** %ptr2
+// CHECK64: store i8* bitcast (void (%struct.C*, ...)* @"\01??_9C@@$BBA@AA" to i8*), i8** %ptr3
+// CHECK64: store i8* bitcast (void (%"struct.(anonymous namespace)::D"*, ...)* @"\01??_9D@?A@@$BA@AA" to i8*), i8** %ptr
// CHECK64: }
}
// Thunk for calling the 1st virtual function in C with no parameters.
-// CHECK32-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C@@$BA@AE"(%struct.C* %this)
-// CHECK32-NOT: unnamed_addr
-// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*)** %{{.*}}, i64 0
-// CHECK32: [[CALLEE:%.*]] = load void (%struct.C*)** [[VPTR]]
-// CHECK32: call x86_thiscallcc void [[CALLEE]](%struct.C* %{{.*}})
-// CHECK32: ret void
+// CHECK32-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C@@$BA@AE"(%struct.C* %this, ...)
+// CHECK32: unnamed_addr
+// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, ...)** %{{.*}}, i64 0
+// CHECK32: [[CALLEE:%.*]] = load void (%struct.C*, ...)** [[VPTR]]
+// CHECK32: musttail call x86_thiscallcc void (%struct.C*, ...)* [[CALLEE]](%struct.C* %{{.*}}, ...)
+// CHECK32-NEXT: ret void
// CHECK32: }
//
-// CHECK64-LABEL: define linkonce_odr void @"\01??_9C@@$BA@AA"(%struct.C* %this)
-// CHECK64-NOT: unnamed_addr
-// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*)** %{{.*}}, i64 0
-// CHECK64: [[CALLEE:%.*]] = load void (%struct.C*)** [[VPTR]]
-// CHECK64: call void [[CALLEE]](%struct.C* %{{.*}})
-// CHECK64: ret void
+// CHECK64-LABEL: define linkonce_odr void @"\01??_9C@@$BA@AA"(%struct.C* %this, ...)
+// CHECK64: unnamed_addr
+// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, ...)** %{{.*}}, i64 0
+// CHECK64: [[CALLEE:%.*]] = load void (%struct.C*, ...)** [[VPTR]]
+// CHECK64: musttail call void (%struct.C*, ...)* [[CALLEE]](%struct.C* %{{.*}}, ...)
+// CHECK64-NEXT: ret void
// CHECK64: }
// Thunk for calling the 2nd virtual function in C, taking int and double as parameters, returning int.
-// CHECK32-LABEL: define linkonce_odr x86_thiscallcc i32 @"\01??_9C@@$B3AE"(%struct.C* %this, i32, double)
-// CHECK32: [[VPTR:%.*]] = getelementptr inbounds i32 (%struct.C*, i32, double)** %{{.*}}, i64 1
-// CHECK32: [[CALLEE:%.*]] = load i32 (%struct.C*, i32, double)** [[VPTR]]
-// CHECK32: [[CALL:%.*]] = call x86_thiscallcc i32 [[CALLEE]](%struct.C* %{{.*}}, i32 %{{.*}}, double %{{.*}})
-// CHECK32: ret i32 [[CALL]]
+// CHECK32-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C@@$B3AE"(%struct.C* %this, ...)
+// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, ...)** %{{.*}}, i64 1
+// CHECK32: [[CALLEE:%.*]] = load void (%struct.C*, ...)** [[VPTR]]
+// CHECK32: musttail call x86_thiscallcc void (%struct.C*, ...)* [[CALLEE]](%struct.C* %{{.*}}, ...)
+// CHECK32-NEXT: ret void
// CHECK32: }
//
-// CHECK64-LABEL: define linkonce_odr i32 @"\01??_9C@@$B7AA"(%struct.C* %this, i32, double)
-// CHECK64: [[VPTR:%.*]] = getelementptr inbounds i32 (%struct.C*, i32, double)** %{{.*}}, i64 1
-// CHECK64: [[CALLEE:%.*]] = load i32 (%struct.C*, i32, double)** [[VPTR]]
-// CHECK64: [[CALL:%.*]] = call i32 [[CALLEE]](%struct.C* %{{.*}}, i32 %{{.*}}, double %{{.*}})
-// CHECK64: ret i32 [[CALL]]
+// CHECK64-LABEL: define linkonce_odr void @"\01??_9C@@$B7AA"(%struct.C* %this, ...)
+// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, ...)** %{{.*}}, i64 1
+// CHECK64: [[CALLEE:%.*]] = load void (%struct.C*, ...)** [[VPTR]]
+// CHECK64: musttail call void (%struct.C*, ...)* [[CALLEE]](%struct.C* %{{.*}}, ...)
+// CHECK64-NEXT: ret void
// CHECK64: }
// Thunk for calling the 3rd virtual function in C, taking an int parameter, returning a struct.
-// CHECK32-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C@@$B7AE"(%struct.C* %this, %struct.S* noalias sret %agg.result, i32)
-// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, %struct.S*, i32)** %{{.*}}, i64 2
-// CHECK32: [[CALLEE:%.*]] = load void (%struct.C*, %struct.S*, i32)** [[VPTR]]
-// CHECK32: call x86_thiscallcc void [[CALLEE]](%struct.C* %{{.*}}, %struct.S* sret %agg.result, i32 %{{.*}})
-// CHECK32: ret void
+// CHECK32-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C@@$B7AE"(%struct.C* %this, ...)
+// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, ...)** %{{.*}}, i64 2
+// CHECK32: [[CALLEE:%.*]] = load void (%struct.C*, ...)** [[VPTR]]
+// CHECK32: musttail call x86_thiscallcc void (%struct.C*, ...)* [[CALLEE]](%struct.C* %{{.*}}, ...)
+// CHECK32-NEXT: ret void
// CHECK32: }
//
-// CHECK64-LABEL: define linkonce_odr void @"\01??_9C@@$BBA@AA"(%struct.C* %this, %struct.S* noalias sret %agg.result, i32)
-// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, %struct.S*, i32)** %{{.*}}, i64 2
-// CHECK64: [[CALLEE:%.*]] = load void (%struct.C*, %struct.S*, i32)** [[VPTR]]
-// CHECK64: call void [[CALLEE]](%struct.C* %{{.*}}, %struct.S* sret %agg.result, i32 %{{.*}})
-// CHECK64: ret void
+// CHECK64-LABEL: define linkonce_odr void @"\01??_9C@@$BBA@AA"(%struct.C* %this, ...)
+// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, ...)** %{{.*}}, i64 2
+// CHECK64: [[CALLEE:%.*]] = load void (%struct.C*, ...)** [[VPTR]]
+// CHECK64: musttail call void (%struct.C*, ...)* [[CALLEE]](%struct.C* %{{.*}}, ...)
+// CHECK64-NEXT: ret void
// CHECK64: }
// Thunk for calling the virtual function in internal class D.
-// CHECK32-LABEL: define internal x86_thiscallcc void @"\01??_9D@?A@@$BA@AE"(%"struct.(anonymous namespace)::D"* %this)
-// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%"struct.(anonymous namespace)::D"*)** %{{.*}}, i64 0
-// CHECK32: [[CALLEE:%.*]] = load void (%"struct.(anonymous namespace)::D"*)** [[VPTR]]
-// CHECK32: call x86_thiscallcc void [[CALLEE]](%"struct.(anonymous namespace)::D"* %{{.*}})
-// CHECK32: ret void
+// CHECK32-LABEL: define internal x86_thiscallcc void @"\01??_9D@?A@@$BA@AE"(%"struct.(anonymous namespace)::D"* %this, ...)
+// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%"struct.(anonymous namespace)::D"*, ...)** %{{.*}}, i64 0
+// CHECK32: [[CALLEE:%.*]] = load void (%"struct.(anonymous namespace)::D"*, ...)** [[VPTR]]
+// CHECK32: musttail call x86_thiscallcc void (%"struct.(anonymous namespace)::D"*, ...)* [[CALLEE]](%"struct.(anonymous namespace)::D"* %{{.*}}, ...)
+// CHECK32-NEXT: ret void
// CHECK32: }
//
-// CHECK64-LABEL: define internal void @"\01??_9D@?A@@$BA@AA"(%"struct.(anonymous namespace)::D"* %this)
-// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%"struct.(anonymous namespace)::D"*)** %{{.*}}, i64 0
-// CHECK64: [[CALLEE:%.*]] = load void (%"struct.(anonymous namespace)::D"*)** [[VPTR]]
-// CHECK64: call void [[CALLEE]](%"struct.(anonymous namespace)::D"* %{{.*}})
-// CHECK64: ret void
+// CHECK64-LABEL: define internal void @"\01??_9D@?A@@$BA@AA"(%"struct.(anonymous namespace)::D"* %this, ...)
+// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%"struct.(anonymous namespace)::D"*, ...)** %{{.*}}, i64 0
+// CHECK64: [[CALLEE:%.*]] = load void (%"struct.(anonymous namespace)::D"*, ...)** [[VPTR]]
+// CHECK64: musttail call void (%"struct.(anonymous namespace)::D"*, ...)* [[CALLEE]](%"struct.(anonymous namespace)::D"* %{{.*}}, ...)
+// CHECK64-NEXT: ret void
// CHECK64: }
// Thunk for calling the fourth virtual function in C, taking a struct parameter
// and returning a struct.
-// CHECK32-LABEL: define linkonce_odr x86_thiscallcc %struct.S* @"\01??_9C@@$BM@AE"(%struct.C* %this, <{ %struct.S*, %struct.U }>* inalloca)
-// CHECK32: [[VPTR:%.*]] = getelementptr inbounds %struct.S* (%struct.C*, <{ %struct.S*, %struct.U }>*)** %{{.*}}, i64 3
-// CHECK32: [[CALLEE:%.*]] = load %struct.S* (%struct.C*, <{ %struct.S*, %struct.U }>*)** [[VPTR]]
-// CHECK32: [[CALL:%.*]] = musttail call x86_thiscallcc %struct.S* [[CALLEE]](%struct.C* %{{.*}}, <{ %struct.S*, %struct.U }>* inalloca %{{.*}})
-// CHECK32-NEXT: ret %struct.S* [[CALL]]
+// CHECK32-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C@@$BM@AE"(%struct.C* %this, ...)
+// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, ...)** %{{.*}}, i64 3
+// CHECK32: [[CALLEE:%.*]] = load void (%struct.C*, ...)** [[VPTR]]
+// CHECK32: musttail call x86_thiscallcc void (%struct.C*, ...)* [[CALLEE]](%struct.C* %{{.*}}, ...)
+// CHECK32-NEXT: ret void
// CHECK32: }
//
-// CHECK64-LABEL: define linkonce_odr void @"\01??_9C@@$BBI@AA"(%struct.C* %this, %struct.S* noalias sret %agg.result, %struct.U*)
-// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, %struct.S*, %struct.U*)** %{{.*}}, i64 3
-// CHECK64: [[CALLEE:%.*]] = load void (%struct.C*, %struct.S*, %struct.U*)** [[VPTR]]
-// CHECK64: call void [[CALLEE]](%struct.C* %{{.*}}, %struct.S* sret %agg.result, %struct.U* %{{.*}})
+// CHECK64-LABEL: define linkonce_odr void @"\01??_9C@@$BBI@AA"(%struct.C* %this, ...)
+// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, ...)** %{{.*}}, i64 3
+// CHECK64: [[CALLEE:%.*]] = load void (%struct.C*, ...)** [[VPTR]]
+// CHECK64: musttail call void (%struct.C*, ...)* [[CALLEE]](%struct.C* %{{.*}}, ...)
// CHECK64: ret void
// CHECK64: }
// Thunk for calling the fifth virtual function in C, taking a struct parameter
// and returning a struct.
-// CHECK32-LABEL: define linkonce_odr x86_fastcallcc void @"\01??_9C@@$BBA@AE"(%struct.C* inreg %this, %struct.S* inreg noalias sret %agg.result, <{ %struct.U }>* inalloca)
-// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, %struct.S*, <{ %struct.U }>*)** %{{.*}}, i64 4
-// CHECK32: [[CALLEE:%.*]] = load void (%struct.C*, %struct.S*, <{ %struct.U }>*)** [[VPTR]]
-// CHECK32: musttail call x86_fastcallcc void [[CALLEE]](%struct.C* inreg %{{.*}}, %struct.S* inreg sret %{{.*}}, <{ %struct.U }>* inalloca %{{.*}})
+// CHECK32-LABEL: define linkonce_odr x86_fastcallcc void @"\01??_9C@@$BBA@AE"(%struct.C* inreg %this, ...)
+// CHECK32: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, ...)** %{{.*}}, i64 4
+// CHECK32: [[CALLEE:%.*]] = load void (%struct.C*, ...)** [[VPTR]]
+// CHECK32: musttail call x86_fastcallcc void (%struct.C*, ...)* [[CALLEE]](%struct.C* inreg %{{.*}}, ...)
// CHECK32-NEXT: ret void
// CHECK32: }
//
-// CHECK64-LABEL: define linkonce_odr void @"\01??_9C@@$BCA@AA"(%struct.C* %this, %struct.S* noalias sret %agg.result, %struct.U*)
-// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, %struct.S*, %struct.U*)** %{{.*}}, i64 4
-// CHECK64: [[CALLEE:%.*]] = load void (%struct.C*, %struct.S*, %struct.U*)** [[VPTR]]
-// CHECK64: call void [[CALLEE]](%struct.C* %{{.*}}, %struct.S* sret %agg.result, %struct.U* %{{.*}})
+// CHECK64-LABEL: define linkonce_odr void @"\01??_9C@@$BCA@AA"(%struct.C* %this, ...)
+// CHECK64: [[VPTR:%.*]] = getelementptr inbounds void (%struct.C*, ...)** %{{.*}}, i64 4
+// CHECK64: [[CALLEE:%.*]] = load void (%struct.C*, ...)** [[VPTR]]
+// CHECK64: musttail call void (%struct.C*, ...)* [[CALLEE]](%struct.C* %{{.*}}, ...)
// CHECK64: ret void
// CHECK64: }
diff --git a/clang/test/CodeGenCXX/microsoft-abi-vmemptr-conflicts.cpp b/clang/test/CodeGenCXX/microsoft-abi-vmemptr-conflicts.cpp
new file mode 100644
index 00000000000..35ff4f3bebe
--- /dev/null
+++ b/clang/test/CodeGenCXX/microsoft-abi-vmemptr-conflicts.cpp
@@ -0,0 +1,101 @@
+// RUN: %clang_cc1 -fno-rtti -emit-llvm -triple=i386-pc-win32 %s -o - | FileCheck %s
+
+// In each test case, we have two member pointers whose thunks have the same
+// vtable offset and same mangling, but their prototypes conflict. The
+// arguments and return type may differ. Therefore, we have to bitcast the
+// function prototype. Unfortunately, if the return types differ, LLVM's
+// optimizers can get upset.
+
+namespace num_params {
+struct A { virtual void a(int); };
+struct B { virtual void b(int, int); };
+struct C : A, B {
+ virtual void a(int);
+ virtual void b(int, int);
+};
+void f(C *c) {
+ (c->*(&C::a))(0);
+ (c->*(&C::b))(0, 0);
+}
+}
+
+// CHECK-LABEL: define void @"\01?f@num_params@@YAXPAUC@1@@Z"(%"struct.num_params::C"* %c)
+// CHECK: call x86_thiscallcc void bitcast (void (%"struct.num_params::C"*, ...)* @"\01??_9C@num_params@@$BA@AE" to void (%"struct.num_params::C"*, i32)*)(%"struct.num_params::C"* %{{.*}}, i32 0)
+// CHECK: call x86_thiscallcc void bitcast (void (%"struct.num_params::C"*, ...)* @"\01??_9C@num_params@@$BA@AE" to void (%"struct.num_params::C"*, i32, i32)*)(%"struct.num_params::C"* %{{.*}}, i32 0, i32 0)
+
+// CHECK-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C@num_params@@$BA@AE"(%"struct.num_params::C"* %this, ...)
+// CHECK: musttail call x86_thiscallcc void (%"struct.num_params::C"*, ...)* %{{.*}}(%"struct.num_params::C"* %{{.*}}, ...)
+// CHECK-NEXT: ret void
+
+namespace i64_return {
+struct A { virtual int a(); };
+struct B { virtual long long b(); };
+struct C : A, B {
+ virtual int a();
+ virtual long long b();
+};
+long long f(C *c) {
+ int x = (c->*(&C::a))();
+ long long y = (c->*(&C::b))();
+ return x + y;
+}
+}
+
+// CHECK-LABEL: define i64 @"\01?f@i64_return@@YA_JPAUC@1@@Z"(%"struct.i64_return::C"* %c)
+// CHECK: call x86_thiscallcc i32 bitcast (void (%"struct.i64_return::C"*, ...)* @"\01??_9C@i64_return@@$BA@AE" to i32 (%"struct.i64_return::C"*)*)(%"struct.i64_return::C"* %{{.*}})
+// CHECK: call x86_thiscallcc i64 bitcast (void (%"struct.i64_return::C"*, ...)* @"\01??_9C@i64_return@@$BA@AE" to i64 (%"struct.i64_return::C"*)*)(%"struct.i64_return::C"* %{{.*}})
+
+// CHECK-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C@i64_return@@$BA@AE"(%"struct.i64_return::C"* %this, ...)
+// CHECK: musttail call x86_thiscallcc void (%"struct.i64_return::C"*, ...)* %{{.*}}(%"struct.i64_return::C"* %{{.*}}, ...)
+// CHECK-NEXT: ret void
+
+namespace sret {
+struct Big { int big[32]; };
+struct A { virtual int a(); };
+struct B { virtual Big b(); };
+struct C : A, B {
+ virtual int a();
+ virtual Big b();
+};
+void f(C *c) {
+ (c->*(&C::a))();
+ Big b((c->*(&C::b))());
+}
+}
+
+// CHECK-LABEL: define void @"\01?f@sret@@YAXPAUC@1@@Z"(%"struct.sret::C"* %c)
+// CHECK: call x86_thiscallcc i32 bitcast (void (%"struct.sret::C"*, ...)* @"\01??_9C@sret@@$BA@AE" to i32 (%"struct.sret::C"*)*)(%"struct.sret::C"* %{{.*}})
+// CHECK: call x86_thiscallcc void bitcast (void (%"struct.sret::C"*, ...)* @"\01??_9C@sret@@$BA@AE" to void (%"struct.sret::C"*, %"struct.sret::Big"*)*)(%"struct.sret::C"* %{{.*}}, %"struct.sret::Big"* sret %{{.*}})
+
+// CHECK-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C@sret@@$BA@AE"(%"struct.sret::C"* %this, ...)
+// CHECK: musttail call x86_thiscallcc void (%"struct.sret::C"*, ...)* %{{.*}}(%"struct.sret::C"* %{{.*}}, ...)
+// CHECK-NEXT: ret void
+
+namespace cdecl_inalloca {
+// Fairly evil, since now we end up doing an inalloca-style call through a
+// thunk that doesn't use inalloca. Hopefully the stacks line up?
+struct Big {
+ Big();
+ ~Big();
+ int big[32];
+};
+struct A { virtual void __cdecl a(); };
+struct B { virtual void __cdecl b(Big); };
+struct C : A, B {
+ virtual void __cdecl a();
+ virtual void __cdecl b(Big);
+};
+void f(C *c) {
+ Big b;
+ (c->*(&C::a))();
+ ((c->*(&C::b))(b));
+}
+}
+
+// CHECK-LABEL: define void @"\01?f@cdecl_inalloca@@YAXPAUC@1@@Z"(%"struct.cdecl_inalloca::C"* %c)
+// CHECK: call void bitcast (void (%"struct.cdecl_inalloca::C"*, ...)* @"\01??_9C@cdecl_inalloca@@$BA@AE" to void (%"struct.cdecl_inalloca::C"*)*)(%"struct.cdecl_inalloca::C"* %{{.*}})
+// CHECK: call void bitcast (void (%"struct.cdecl_inalloca::C"*, ...)* @"\01??_9C@cdecl_inalloca@@$BA@AE" to void (<{ %"struct.cdecl_inalloca::C"*, %"struct.cdecl_inalloca::Big" }>*)*)(<{ %"struct.cdecl_inalloca::C"*, %"struct.cdecl_inalloca::Big" }>* inalloca %{{.*}})
+
+// CHECK-LABEL: define linkonce_odr void @"\01??_9C@cdecl_inalloca@@$BA@AE"(%"struct.cdecl_inalloca::C"* %this, ...)
+// CHECK: musttail call void (%"struct.cdecl_inalloca::C"*, ...)* %{{.*}}(%"struct.cdecl_inalloca::C"* %{{.*}}, ...)
+// CHECK-NEXT: ret void
diff --git a/clang/test/CodeGenCXX/microsoft-abi-vmemptr-fastcall.cpp b/clang/test/CodeGenCXX/microsoft-abi-vmemptr-fastcall.cpp
new file mode 100644
index 00000000000..9d55383d656
--- /dev/null
+++ b/clang/test/CodeGenCXX/microsoft-abi-vmemptr-fastcall.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -triple i686-pc-windows-msvc %s -emit-llvm-only -verify
+
+// We reject this because LLVM doesn't forward the second regparm through the
+// thunk.
+
+struct A {
+ virtual void __fastcall f(int a, int b);
+};
+void (__fastcall A::*doit())(int, int) {
+ return &A::f; // expected-error {{cannot compile this pointer to fastcall virtual member function yet}}
+}
OpenPOWER on IntegriCloud