https://github.com/marlus updated 
https://github.com/llvm/llvm-project/pull/204139

>From 055db081f85fe617fa1025e2bf582338e4d747bd Mon Sep 17 00:00:00 2001
From: Marlus Cadanus da Costa <[email protected]>
Date: Tue, 16 Jun 2026 08:42:14 -0400
Subject: [PATCH 1/2] [Clang] Fix offsetof sign-extending unsigned array
 indices >= 128

When evaluating __builtin_offsetof with an unsigned integer array index
(e.g. uint8_t, uint16_t) whose value has the high bit set, Clang was
calling getSExtValue() on the APSInt index, which sign-extends the value
and produces a large bogus offset.

Fix this by checking whether the APSInt is unsigned and using
getZExtValue() in that case instead.

Fixes #199319
---
 clang/lib/AST/ExprConstant.cpp                |  3 +-
 clang/test/Sema/offsetof-unsigned-index.c     | 25 +++++++++++++++
 .../test/SemaCXX/offsetof-unsigned-index.cpp  | 31 +++++++++++++++++++
 3 files changed, 58 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/Sema/offsetof-unsigned-index.c
 create mode 100644 clang/test/SemaCXX/offsetof-unsigned-index.cpp

diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index bc98c0d86bb65..a2a3349b21baf 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -19284,7 +19284,8 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const 
OffsetOfExpr *OOE) {
         return Error(OOE);
       CurrentType = AT->getElementType();
       CharUnits ElementSize = Info.Ctx.getTypeSizeInChars(CurrentType);
-      Result += IdxResult.getSExtValue() * ElementSize;
+      Result += (IdxResult.isUnsigned() ? (int64_t)IdxResult.getZExtValue()
+                                        : IdxResult.getSExtValue()) * 
ElementSize;
       break;
     }
 
diff --git a/clang/test/Sema/offsetof-unsigned-index.c 
b/clang/test/Sema/offsetof-unsigned-index.c
new file mode 100644
index 0000000000000..480e486fbad72
--- /dev/null
+++ b/clang/test/Sema/offsetof-unsigned-index.c
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -triple x86_64-linux-gnu
+// RUN: %clang_cc1 -fsyntax-only -verify %s -triple x86_64-linux-gnu 
-fexperimental-new-constant-interpreter
+
+// expected-no-diagnostics
+
+// Test that offsetof correctly zero-extends unsigned array indices >= 128.
+// Previously, Clang would sign-extend uint8_t indices >= 128, producing
+// a large bogus offset value instead of the correct one.
+// https://github.com/llvm/llvm-project/issues/199319
+
+#include <stdint.h>
+#include <stddef.h>
+
+struct MyStruct {
+    void *ptrs[256];
+};
+
+_Static_assert(__builtin_offsetof(struct MyStruct, ptrs[(uint8_t)127]) == 127 
* sizeof(void *),
+               "offsetof with uint8_t index 127 should be correct");
+
+_Static_assert(__builtin_offsetof(struct MyStruct, ptrs[(uint8_t)128]) == 128 
* sizeof(void *),
+               "offsetof with uint8_t index 128 should be correctly 
zero-extended, not sign-extended");
+
+_Static_assert(__builtin_offsetof(struct MyStruct, ptrs[(uint8_t)255]) == 255 
* sizeof(void *),
+               "offsetof with uint8_t index 255 should be correctly 
zero-extended, not sign-extended");
diff --git a/clang/test/SemaCXX/offsetof-unsigned-index.cpp 
b/clang/test/SemaCXX/offsetof-unsigned-index.cpp
new file mode 100644
index 0000000000000..50bf50ef0fc35
--- /dev/null
+++ b/clang/test/SemaCXX/offsetof-unsigned-index.cpp
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -triple x86_64-linux-gnu -std=c++11
+// RUN: %clang_cc1 -fsyntax-only -verify %s -triple x86_64-linux-gnu 
-std=c++11 -fexperimental-new-constant-interpreter
+
+// expected-no-diagnostics
+
+// Test that offsetof correctly zero-extends unsigned array indices >= 128.
+// Previously, Clang would sign-extend uint8_t/uint16_t indices whose high bit
+// was set, producing a large bogus offset value instead of the correct one.
+// https://github.com/llvm/llvm-project/issues/199319
+
+#include <cstdint>
+#include <cstddef>
+
+struct MyStruct {
+    void *ptrs[256];
+};
+
+// uint8_t index: values >= 128 were incorrectly sign-extended
+static_assert(__builtin_offsetof(MyStruct, ptrs[(uint8_t)127]) == 127 * 
sizeof(void *),
+              "offsetof with uint8_t index 127 should be correct");
+static_assert(__builtin_offsetof(MyStruct, ptrs[(uint8_t)128]) == 128 * 
sizeof(void *),
+              "offsetof with uint8_t index 128 should be correctly 
zero-extended");
+static_assert(__builtin_offsetof(MyStruct, ptrs[(uint8_t)255]) == 255 * 
sizeof(void *),
+              "offsetof with uint8_t index 255 should be correctly 
zero-extended");
+
+// uint16_t index: values >= 32768 were also affected
+struct BigStruct {
+    char data[65536];
+};
+static_assert(__builtin_offsetof(BigStruct, data[(uint16_t)32768]) == 32768,
+              "offsetof with uint16_t index 32768 should be correctly 
zero-extended");

>From 71f80764449046ef26d2ad399fcd2853359a2a6a Mon Sep 17 00:00:00 2001
From: Cadanus da Costa <[email protected]>
Date: Tue, 16 Jun 2026 14:52:53 -0400
Subject: [PATCH 2/2] Apply clang-format

---
 clang/lib/AST/ExprConstant.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index a2a3349b21baf..eb76c10076669 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -19285,7 +19285,8 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const 
OffsetOfExpr *OOE) {
       CurrentType = AT->getElementType();
       CharUnits ElementSize = Info.Ctx.getTypeSizeInChars(CurrentType);
       Result += (IdxResult.isUnsigned() ? (int64_t)IdxResult.getZExtValue()
-                                        : IdxResult.getSExtValue()) * 
ElementSize;
+                                        : IdxResult.getSExtValue()) *
+                ElementSize;
       break;
     }
 

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to