[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