Skip to content

Commit 13008aa

Browse files
authored
[clang][Interp] Diagnose pointer subtraction on zero-size arrays (llvm#103015)
1 parent 3cab7c5 commit 13008aa

File tree

3 files changed

+34
-1
lines changed

3 files changed

+34
-1
lines changed

clang/lib/AST/Interp/Interp.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1987,6 +1987,22 @@ inline bool SubPtr(InterpState &S, CodePtr OpPC) {
19871987
const Pointer &LHS = S.Stk.pop<Pointer>();
19881988
const Pointer &RHS = S.Stk.pop<Pointer>();
19891989

1990+
for (const Pointer &P : {LHS, RHS}) {
1991+
if (P.isZeroSizeArray()) {
1992+
QualType PtrT = P.getType();
1993+
while (auto *AT = dyn_cast<ArrayType>(PtrT))
1994+
PtrT = AT->getElementType();
1995+
1996+
QualType ArrayTy = S.getCtx().getConstantArrayType(
1997+
PtrT, APInt::getZero(1), nullptr, ArraySizeModifier::Normal, 0);
1998+
S.FFDiag(S.Current->getSource(OpPC),
1999+
diag::note_constexpr_pointer_subtraction_zero_size)
2000+
<< ArrayTy;
2001+
2002+
return false;
2003+
}
2004+
}
2005+
19902006
if (RHS.isZero()) {
19912007
S.Stk.push<T>(T::from(LHS.getIndex()));
19922008
return true;

clang/lib/AST/Interp/Pointer.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -613,7 +613,11 @@ class Pointer {
613613
bool isElementPastEnd() const { return Offset == PastEndMark; }
614614

615615
/// Checks if the pointer is pointing to a zero-size array.
616-
bool isZeroSizeArray() const { return getFieldDesc()->isZeroSizeArray(); }
616+
bool isZeroSizeArray() const {
617+
if (const auto *Desc = getFieldDesc())
618+
return Desc->isZeroSizeArray();
619+
return false;
620+
}
617621

618622
/// Dereferences the pointer, if it's live.
619623
template <typename T> T &deref() const {

clang/test/AST/Interp/arrays.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -632,3 +632,16 @@ constexpr int fail(const int &p) {
632632
}
633633
static_assert(fail(*(&(&(*(*&(&zs[2] - 1)[0] + 2 - 2))[2])[-1][2] - 2)) == 11, ""); // both-error {{not an integral constant expression}} \
634634
// both-note {{in call to}}
635+
636+
namespace ZeroSizeTypes {
637+
constexpr int (*p1)[0] = 0, (*p2)[0] = 0;
638+
constexpr int k = p2 - p1; // both-error {{constexpr variable 'k' must be initialized by a constant expression}} \
639+
// both-note {{subtraction of pointers to type 'int[0]' of zero size}} \
640+
// both-warning {{subtraction of pointers to type 'int[0]' of zero size has undefined behavior}}
641+
642+
int arr[5][0];
643+
constexpr int f() { // both-error {{never produces a constant expression}}
644+
return &arr[3] - &arr[0]; // both-note {{subtraction of pointers to type 'int[0]' of zero size}} \
645+
// both-warning {{subtraction of pointers to type 'int[0]' of zero size has undefined behavior}}
646+
}
647+
}

0 commit comments

Comments
 (0)