]> granicus.if.org Git - clang/commitdiff
Handle pointer arithmetic on function pointers.
authorDaniel Dunbar <daniel@zuster.org>
Fri, 23 Jan 2009 18:51:09 +0000 (18:51 +0000)
committerDaniel Dunbar <daniel@zuster.org>
Fri, 23 Jan 2009 18:51:09 +0000 (18:51 +0000)
 - <rdar://problem/6518844> Clang-generated bitcode crashes LLVM while compiling function pointer addition expression

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@62857 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGExprScalar.cpp
test/CodeGen/pointer-arithmetic.c

index f21373a53831d38d0f83d8c955e26ec82e845d2b..fc87726a2115f07c9a1253bb02215b61e7573399 100644 (file)
@@ -872,11 +872,14 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) {
   // FIXME: What about a pointer to a VLA?
   Value *Ptr, *Idx;
   Expr *IdxExp;
-  if (isa<llvm::PointerType>(Ops.LHS->getType())) {  // pointer + int
+  const PointerType *PT;
+  if ((PT = Ops.E->getLHS()->getType()->getAsPointerType())) {
     Ptr = Ops.LHS;
     Idx = Ops.RHS;
     IdxExp = Ops.E->getRHS();
   } else {                                           // int + pointer
+    PT = Ops.E->getRHS()->getType()->getAsPointerType();
+    assert(PT && "Invalid add expr");
     Ptr = Ops.RHS;
     Idx = Ops.LHS;
     IdxExp = Ops.E->getLHS();
@@ -892,6 +895,17 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) {
     else
       Idx = Builder.CreateZExt(Idx, IdxType, "idx.ext");
   }
+
+  // Explicitly handle GNU void* and function pointer arithmetic
+  // extensions. The GNU void* casts amount to no-ops since our void*
+  // type is i8*, but this is future proof.
+  const QualType ElementType = PT->getPointeeType();
+  if (ElementType->isVoidType() || ElementType->isFunctionType()) {
+    const llvm::Type *i8Ty = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+    Value *Casted = Builder.CreateBitCast(Ptr, i8Ty);
+    Value *Res = Builder.CreateGEP(Casted, Idx, "sub.ptr");
+    return Builder.CreateBitCast(Res, Ptr->getType());
+  } 
   
   return Builder.CreateGEP(Ptr, Idx, "add.ptr");
 }
@@ -900,6 +914,8 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) {
   if (!isa<llvm::PointerType>(Ops.LHS->getType()))
     return Builder.CreateSub(Ops.LHS, Ops.RHS, "sub");
 
+  const QualType LHSType = Ops.E->getLHS()->getType();
+  const QualType LHSElementType = LHSType->getAsPointerType()->getPointeeType();
   if (!isa<llvm::PointerType>(Ops.RHS->getType())) {
     // pointer - int
     Value *Idx = Ops.RHS;
@@ -916,16 +932,23 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) {
     Idx = Builder.CreateNeg(Idx, "sub.ptr.neg");
     
     // FIXME: The pointer could point to a VLA.
-    // The GNU void* - int case is automatically handled here because
-    // our LLVM type for void* is i8*.
+
+    // Explicitly handle GNU void* and function pointer arithmetic
+    // extensions. The GNU void* casts amount to no-ops since our
+    // void* type is i8*, but this is future proof.
+    if (LHSElementType->isVoidType() || LHSElementType->isFunctionType()) {
+      const llvm::Type *i8Ty = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+      Value *LHSCasted = Builder.CreateBitCast(Ops.LHS, i8Ty);
+      Value *Res = Builder.CreateGEP(LHSCasted, Idx, "sub.ptr");
+      return Builder.CreateBitCast(Res, Ops.LHS->getType());
+    } 
+      
     return Builder.CreateGEP(Ops.LHS, Idx, "sub.ptr");
   } else {
     // pointer - pointer
     Value *LHS = Ops.LHS;
     Value *RHS = Ops.RHS;
   
-    const QualType LHSType = Ops.E->getLHS()->getType();
-    const QualType LHSElementType = LHSType->getAsPointerType()->getPointeeType();
     uint64_t ElementSize;
 
     // Handle GCC extension for pointer arithmetic on void* types.
index 3133c9effe4eaef871b62be38c1a52d32755a596..23a6ab41a1c62cd02364e96775a0f711f78ea6fa 100644 (file)
@@ -1,7 +1,22 @@
-// RUN: clang -emit-llvm %s -o %t
+// RUN: clang -S %s -o %t
 
 typedef int Int;
 
-int test1(int *a, Int *b) { return a - b; }
+int f0(int *a, Int *b) { return a - b; }
 
-int test2(const char *a, char *b) { return b - a; }
+int f1(const char *a, char *b) { return b - a; }
+
+// GNU extensions
+typedef void (*FP)(void);
+void *f2(void *a, int b) { return a + b; }
+void *f2_1(void *a, int b) { return (a += b); }
+void *f3(int a, void *b) { return a + b; }
+void *f3_1(int a, void *b) { return (a += b); }
+void *f4(void *a, int b) { return a - b; }
+void *f4_1(void *a, int b) { return (a -= b); }
+FP f5(FP a, int b) { return a + b; }
+FP f5_1(FP a, int b) { return (a += b); }
+FP f6(int a, FP b) { return a + b; }
+FP f6_1(int a, FP b) { return (a += b); }
+FP f7(FP a, int b) { return a - b; }
+FP f7_1(FP a, int b) { return (a -= b); }