[clang] ffcdf47 - [clang][Interp] Allow adding an offset to a function pointer

Timm Bäder via cfe-commits cfe-commits at lists.llvm.org
Wed Feb 21 08:18:37 PST 2024


Author: Timm Bäder
Date: 2024-02-21T17:18:22+01:00
New Revision: ffcdf47bc443b36754c36bd6e1a77b4163657a00

URL: https://github.com/llvm/llvm-project/commit/ffcdf47bc443b36754c36bd6e1a77b4163657a00
DIFF: https://github.com/llvm/llvm-project/commit/ffcdf47bc443b36754c36bd6e1a77b4163657a00.diff

LOG: [clang][Interp] Allow adding an offset to a function pointer

Pretty sure this isn't doing anything, but it fixes a test and
is generally the right thing to do.
Fixing the behavior will come later.

Added: 
    clang/test/AST/Interp/pointer-addition.c

Modified: 
    clang/lib/AST/Interp/ByteCodeExprGen.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
index d11d05dd709d5e..0b08309e4e6e02 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -1403,12 +1403,11 @@ bool ByteCodeExprGen<Emitter>::VisitPointerCompoundAssignOperator(
 
   if (!LT || !RT)
     return false;
-  assert(*LT == PT_Ptr);
 
   if (!visit(LHS))
     return false;
 
-  if (!this->emitLoadPtr(LHS))
+  if (!this->emitLoad(*LT, LHS))
     return false;
 
   if (!visit(RHS))
@@ -2828,7 +2827,7 @@ bool ByteCodeExprGen<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
     if (!this->visit(SubExpr))
       return false;
 
-    if (T == PT_Ptr) {
+    if (T == PT_Ptr || T == PT_FnPtr) {
       if (!this->emitIncPtr(E))
         return false;
 
@@ -2846,7 +2845,7 @@ bool ByteCodeExprGen<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
     if (!this->visit(SubExpr))
       return false;
 
-    if (T == PT_Ptr) {
+    if (T == PT_Ptr || T == PT_FnPtr) {
       if (!this->emitDecPtr(E))
         return false;
 
@@ -2864,7 +2863,7 @@ bool ByteCodeExprGen<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
     if (!this->visit(SubExpr))
       return false;
 
-    if (T == PT_Ptr) {
+    if (T == PT_Ptr || T == PT_FnPtr) {
       if (!this->emitLoadPtr(E))
         return false;
       if (!this->emitConstUint8(1, E))
@@ -2903,7 +2902,7 @@ bool ByteCodeExprGen<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
     if (!this->visit(SubExpr))
       return false;
 
-    if (T == PT_Ptr) {
+    if (T == PT_Ptr || T == PT_FnPtr) {
       if (!this->emitLoadPtr(E))
         return false;
       if (!this->emitConstUint8(1, E))

diff  --git a/clang/test/AST/Interp/pointer-addition.c b/clang/test/AST/Interp/pointer-addition.c
new file mode 100644
index 00000000000000..80ab670e8bface
--- /dev/null
+++ b/clang/test/AST/Interp/pointer-addition.c
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 %s -fsyntax-only -verify=gnu,expected -pedantic -Wextra -std=c11 -fexperimental-new-constant-interpreter
+// RUN: %clang_cc1 %s -fsyntax-only -triple i686-unknown-unknown -verify=gnu,expected -pedantic -Wextra -std=c11 -fexperimental-new-constant-interpreter
+// RUN: %clang_cc1 %s -fsyntax-only -triple x86_64-unknown-unknown -verify=gnu,expected -pedantic -Wextra -std=c11 -fexperimental-new-constant-interpreter
+// RUN: %clang_cc1 %s -fsyntax-only -verify -pedantic -Wextra -Wno-gnu -std=c11 -fexperimental-new-constant-interpreter
+
+typedef __INTPTR_TYPE__ intptr_t;
+typedef struct S S; // expected-note 4 {{forward declaration of 'struct S'}}
+extern _Atomic(S*) e;
+void a(S* b, void* c) {
+  void (*fp)(int) = 0;
+  b++;       // expected-error {{arithmetic on a pointer to an incomplete type}}
+  b += 1;    // expected-error {{arithmetic on a pointer to an incomplete type}}
+  c++;       // gnu-warning {{arithmetic on a pointer to void is a GNU extension}}
+  c += 1;    // gnu-warning {{arithmetic on a pointer to void is a GNU extension}}
+  c--;       // gnu-warning {{arithmetic on a pointer to void is a GNU extension}}
+  c -= 1;    // gnu-warning {{arithmetic on a pointer to void is a GNU extension}}
+  (void) c[1]; // gnu-warning {{subscript of a pointer to void is a GNU extension}}
+  b = 1+b;   // expected-error {{arithmetic on a pointer to an incomplete type}}
+  /* The next couple tests are only pedantic warnings in gcc */
+  void (*d)(S*,void*) = a;
+  d += 1;    // gnu-warning {{arithmetic on a pointer to the function type 'void (S *, void *)' (aka 'void (struct S *, void *)') is a GNU extension}}
+  d++;       // gnu-warning {{arithmetic on a pointer to the function type 'void (S *, void *)' (aka 'void (struct S *, void *)') is a GNU extension}}
+  d--;       // gnu-warning {{arithmetic on a pointer to the function type 'void (S *, void *)' (aka 'void (struct S *, void *)') is a GNU extension}}
+  d -= 1;    // gnu-warning {{arithmetic on a pointer to the function type 'void (S *, void *)' (aka 'void (struct S *, void *)') is a GNU extension}}
+  (void)(1 + d); // gnu-warning {{arithmetic on a pointer to the function type 'void (S *, void *)' (aka 'void (struct S *, void *)') is a GNU extension}}
+  e++;       // expected-error {{arithmetic on a pointer to an incomplete type}}
+  intptr_t i = (intptr_t)b;
+  char *f = (char*)0 + i; // gnu-warning {{arithmetic on a null pointer treated as a cast from integer to pointer is a GNU extension}}
+  // Cases that don't match the GNU inttoptr idiom get a 
diff erent warning.
+  f = (char*)0 - i; // expected-warning {{performing pointer arithmetic on a null pointer has undefined behavior}}
+  int *g = (int*)0 + i; // expected-warning {{performing pointer arithmetic on a null pointer has undefined behavior}}
+}


        


More information about the cfe-commits mailing list