]> granicus.if.org Git - clang/commitdiff
Fix another pointer-to-member function miscompile, this time when trying to call...
authorAnders Carlsson <andersca@mac.com>
Thu, 4 Feb 2010 17:08:48 +0000 (17:08 +0000)
committerAnders Carlsson <andersca@mac.com>
Thu, 4 Feb 2010 17:08:48 +0000 (17:08 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@95307 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGExprCXX.cpp
test/CodeGenCXX/member-function-pointer-calls.cpp [new file with mode: 0644]

index 4253d18c390a3a6f3212de0425649557789619c3..ab54976e2874fbb50ea125df881e6c2c4b0248f6 100644 (file)
@@ -159,8 +159,7 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E,
     CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(RD, FPT),
                                    FPT->isVariadic());
 
-  const llvm::Type *Int8PtrTy = 
-    llvm::Type::getInt8Ty(VMContext)->getPointerTo();
+  const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext);
 
   // Get the member function pointer.
   llvm::Value *MemFnPtr = 
@@ -206,19 +205,20 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E,
   Builder.CreateCondBr(IsVirtual, FnVirtual, FnNonVirtual);
   EmitBlock(FnVirtual);
   
-  const llvm::Type *VTableTy = 
-    FTy->getPointerTo()->getPointerTo()->getPointerTo();
+  const llvm::Type *VtableTy = 
+    FTy->getPointerTo()->getPointerTo();
 
-  llvm::Value *VTable = Builder.CreateBitCast(This, VTableTy);
-  VTable = Builder.CreateLoad(VTable);
+  llvm::Value *Vtable = Builder.CreateBitCast(This, VtableTy->getPointerTo());
+  Vtable = Builder.CreateLoad(Vtable);
   
-  VTable = Builder.CreateGEP(VTable, FnAsInt, "fn");
+  Vtable = Builder.CreateBitCast(Vtable, Int8PtrTy);
+  llvm::Value *VtableOffset = 
+    Builder.CreateSub(FnAsInt, llvm::ConstantInt::get(PtrDiffTy, 1));
   
-  // Since the function pointer is 1 plus the virtual table offset, we
-  // subtract 1 by using a GEP.
-  VTable = Builder.CreateConstGEP1_64(VTable, (uint64_t)-1);
+  Vtable = Builder.CreateGEP(Vtable, VtableOffset, "fn");
+  Vtable = Builder.CreateBitCast(Vtable, VtableTy);
   
-  llvm::Value *VirtualFn = Builder.CreateLoad(VTable, "virtualfn");
+  llvm::Value *VirtualFn = Builder.CreateLoad(Vtable, "virtualfn");
   
   EmitBranch(FnEnd);
   EmitBlock(FnNonVirtual);
diff --git a/test/CodeGenCXX/member-function-pointer-calls.cpp b/test/CodeGenCXX/member-function-pointer-calls.cpp
new file mode 100644 (file)
index 0000000..e1f2eb7
--- /dev/null
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -O3 -o - | FileCheck %s
+struct A {
+  virtual int vf1() { return 1; }
+  virtual int vf2() { return 2; }
+};
+
+int f(A* a, int (A::*fp)()) {
+  return (a->*fp)();
+}
+
+// CHECK: define i32 @_Z2g1v()
+int g1() {
+  A a;
+  
+  // CHECK: call i32 @_ZN1A3vf1Ev
+  // CHECK-NEXT: ret i32
+  return f(&a, &A::vf1);
+}
+
+int g2() {
+  A a;
+  
+  // CHECK: call i32 @_ZN1A3vf2Ev
+  // CHECK-NEXT: ret i32
+  return f(&a, &A::vf2);
+}