[clang] [clang] Follow-up fixes for offsetof unsigned index change (PR #207808)
Marlus Cadanus da Costa via cfe-commits
cfe-commits at lists.llvm.org
Wed Jul 8 07:03:11 PDT 2026
https://github.com/marlus updated https://github.com/llvm/llvm-project/pull/207808
>From 379569598a352c60fa270eefe26d89e52fb5ad82 Mon Sep 17 00:00:00 2001
From: Cadanus da Costa <maccosta at beenox.com>
Date: Mon, 6 Jul 2026 14:27:08 -0400
Subject: [PATCH 1/2] [clang] Follow-up fixes for offsetof unsigned index
change
- Rename CastNoOverflow to CastAPToOffsetIndex for clarity
- Add parentheses in overflow guard condition in InterpBuiltin.cpp
- Improve comment explaining why 0x8000000000000000 is rejected
Addresses post-merge review comments from shafik.
---
clang/lib/AST/ByteCode/Compiler.cpp | 2 +-
clang/lib/AST/ByteCode/Interp.h | 7 ++++---
clang/lib/AST/ByteCode/InterpBuiltin.cpp | 2 +-
clang/lib/AST/ByteCode/Opcodes.td | 5 +++--
clang/test/Sema/offsetof-unsigned-index.c | 4 +++-
5 files changed, 12 insertions(+), 8 deletions(-)
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index b4468c94ff675..4e070d8237bbb 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -4001,7 +4001,7 @@ bool Compiler<Emitter>::VisitOffsetOfExpr(const OffsetOfExpr *E) {
if (IndexT == PT_IntAP || IndexT == PT_IntAPS) {
if (!this->visit(ArrayIndexExpr))
return false;
- if (!this->emitCastNoOverflow(IndexT, E))
+ if (!this->emitCastAPToOffsetIndex(IndexT, E))
return false;
continue;
}
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index d16a00414f45a..b70015aa67ab7 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -2893,10 +2893,11 @@ bool CastAPS(InterpState &S, uint32_t BitWidth) {
return true;
}
-// Cast an AP integer to Sint64, failing constant evaluation if the value is
-// negative or too large to fit (i.e. truncation would change the value).
+// Cast an AP integer to Sint64 for use as an offsetof array index, failing
+// constant evaluation if the value is negative or too large to fit in Sint64
+// (i.e. truncation would change the value).
template <PrimType Name, class T = typename PrimConv<Name>::T>
-bool CastNoOverflow(InterpState &S, CodePtr OpPC) {
+bool CastAPToOffsetIndex(InterpState &S, CodePtr OpPC) {
T Source = S.Stk.pop<T>();
APSInt Val = Source.toAPSInt();
if (Val.isNegative() || Val.getActiveBits() > 63)
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index 70717720c592d..57f3d793d4785 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -6824,7 +6824,7 @@ bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E,
CurrentType = AT->getElementType();
CharUnits ElementSize = S.getASTContext().getTypeSizeInChars(CurrentType);
int64_t ElemSize = ElementSize.getQuantity();
- if (Index != 0 && ElemSize > llvm::maxIntN(64) / Index) {
+ if ((Index != 0) && (ElemSize > (llvm::maxIntN(64) / Index))) {
S.FFDiag(S.Current->getLocation(OpPC),
diag::note_constexpr_offsetof_overflow)
<< S.Current->getRange(OpPC);
diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td
index 577c8523ab6c3..7b57849ebddb7 100644
--- a/clang/lib/AST/ByteCode/Opcodes.td
+++ b/clang/lib/AST/ByteCode/Opcodes.td
@@ -787,8 +787,9 @@ def APOnlyTypeClass : TypeClass {
let Types = [IntAP, IntAPS];
}
-// Cast from an AP integer type to Sint64, failing if the value doesn't fit.
-def CastNoOverflow : Opcode {
+// Cast from an AP integer type to Sint64 for use as an offsetof array index,
+// failing if the value is negative or doesn't fit in Sint64.
+def CastAPToOffsetIndex : Opcode {
let Types = [APOnlyTypeClass];
let HasGroup = 1;
}
diff --git a/clang/test/Sema/offsetof-unsigned-index.c b/clang/test/Sema/offsetof-unsigned-index.c
index 56396eb2a12e6..16d6989fe0a85 100644
--- a/clang/test/Sema/offsetof-unsigned-index.c
+++ b/clang/test/Sema/offsetof-unsigned-index.c
@@ -34,7 +34,9 @@ _Static_assert(__builtin_offsetof(struct BigStruct, data[(uint16_t)32768]) == 32
struct NegIdxStruct { int a; int x[1]; };
_Static_assert(__builtin_offsetof(struct NegIdxStruct, x[-1]) == 0, ""); // expected-error {{not an integral constant expression}}
-// __uint128_t indices >= 0x8000000000000000 must be rejected.
+// __uint128_t indices >= 0x8000000000000000 must be rejected: this value has
+// bit 63 set, so getActiveBits() > 63, which our guard treats as too large
+// for a signed 64-bit offset index.
_Static_assert(__builtin_offsetof(struct NegIdxStruct, x[(__uint128_t)0x8000000000000000]) == 0, ""); // expected-error {{not an integral constant expression}}
// Small __uint128_t values that fit in int64_t must work correctly.
>From 72ba6b6258cb63cb425ea724ab07aef2fc98d876 Mon Sep 17 00:00:00 2001
From: Marlus Cadanus da Costa <marluscadanus at gmail.com>
Date: Wed, 8 Jul 2026 10:02:56 -0400
Subject: [PATCH 2/2] Fix parentheses in offsetof overflow guard per review
feedback
---
clang/lib/AST/ByteCode/InterpBuiltin.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index 57f3d793d4785..766f89807706d 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -6824,7 +6824,7 @@ bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E,
CurrentType = AT->getElementType();
CharUnits ElementSize = S.getASTContext().getTypeSizeInChars(CurrentType);
int64_t ElemSize = ElementSize.getQuantity();
- if ((Index != 0) && (ElemSize > (llvm::maxIntN(64) / Index))) {
+ if (Index != 0 && ElemSize > (llvm::maxIntN(64) / Index)) {
S.FFDiag(S.Current->getLocation(OpPC),
diag::note_constexpr_offsetof_overflow)
<< S.Current->getRange(OpPC);
More information about the cfe-commits
mailing list