Author: Aditya Medhane Date: 2026-09-01T22:36:29+05:30 New Revision: 5407e6e55fe7daf8c48a801e607fa118f65b62be
URL: https://github.com/llvm/llvm-project/commit/5407e6e55fe7daf8c48a801e607fa118f65b62be DIFF: https://github.com/llvm/llvm-project/commit/5407e6e55fe7daf8c48a801e607fa118f65b62be.diff LOG: [clang][Sema] Don't report pointer subtraction on a VLA as zero size (#217465) CheckSubtractionOperands warns when the pointee type has zero size, because the subtraction divides by that size. A variably modified type such as int[n] has no statically known size, and getTypeInfoImpl models it as zero, so the check reported it as an empty type even though its size is only determined at run time. Instead of trusting the static size, decide whether the size is provably zero: walk the array dimensions, folding each variable bound as an integer constant expression, and warn only when a dimension is provably zero or the base element type has zero size. Genuinely empty cases keep warning, including int[0], zero-sized structs, and VLAs of zero-sized types such as struct Empty vla[n] or int vla[n][0]. Fixes #28328 Added: clang/test/SemaCXX/pointer-sub-zero-size.cpp Modified: clang/docs/ReleaseNotes.md clang/lib/Sema/SemaExpr.cpp clang/test/Analysis/pointer-sub.c clang/test/Sema/empty1.c Removed: ################################################################################ diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index 3984646cb2d7e..2f65f2ea0a9f2 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -454,6 +454,12 @@ features cannot lower the translation-unit ABI level; - Clang now diagnoses more details when a constraint evaluates to false. +- `-Wpointer-arith` no longer reports subtraction of pointers to a variably + modified type, such as `int[n]`, as a subtraction of pointers to a type of + zero size, unless the size is provably zero: a zero-sized base element or a + dimension that is a zero integer constant, as in `struct Empty vla[n]` or + `int vla[n][0]`. (#GH28328) + ### Improvements to Clang's time-trace ### Improvements to Coverage Mapping diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 34f6ccdbc2fe6..ad703248cf325 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -11791,6 +11791,26 @@ QualType Sema::CheckAdditionOperands(ExprResult &LHS, ExprResult &RHS, return PExp->getType(); } +/// Determine whether the size of \p T is provably zero: some array dimension +/// is provably zero or the base element type has zero size. A variable +/// dimension that does not fold to an integer constant is assumed nonzero. +static bool isProvablyZeroSize(const ASTContext &Ctx, QualType T) { + while (const ArrayType *AT = Ctx.getAsArrayType(T)) { + if (const auto *CAT = dyn_cast<ConstantArrayType>(AT)) { + if (CAT->isZeroSize()) + return true; + } else if (const auto *VAT = dyn_cast<VariableArrayType>(AT)) { + if (const Expr *Bound = VAT->getSizeExpr()) + if (std::optional<llvm::APSInt> Size = + Bound->getIntegerConstantExpr(Ctx)) + if (*Size == 0) + return true; + } + T = AT->getElementType(); + } + return !T->isIncompleteType() && Ctx.getTypeSizeInChars(T).isZero(); +} + // C99 6.5.6 QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, @@ -11925,15 +11945,13 @@ QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS, // The pointee type may have zero size. As an extension, a structure or // union may have zero size or an array may have zero length. In this - // case subtraction does not make sense. - if (!rpointee->isVoidType() && !rpointee->isFunctionType()) { - CharUnits ElementSize = Context.getTypeSizeInChars(rpointee); - if (ElementSize.isZero()) { - Diag(Loc,diag::warn_sub_ptr_zero_size_types) - << rpointee.getUnqualifiedType() - << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); - } - } + // case subtraction does not make sense. For a variably modified type, + // warn only when the size is provably zero. + if (!rpointee->isVoidType() && !rpointee->isFunctionType() && + isProvablyZeroSize(Context, rpointee)) + Diag(Loc, diag::warn_sub_ptr_zero_size_types) + << rpointee.getUnqualifiedType() << LHS.get()->getSourceRange() + << RHS.get()->getSourceRange(); if (CompLHSTy) *CompLHSTy = LHS.get()->getType(); return Context.getPointerDiffType(); diff --git a/clang/test/Analysis/pointer-sub.c b/clang/test/Analysis/pointer-sub.c index 25fb7f043d468..d2155e110ba54 100644 --- a/clang/test/Analysis/pointer-sub.c +++ b/clang/test/Analysis/pointer-sub.c @@ -65,11 +65,9 @@ void f4(void) { int (*p)[m] = a; // p == &a[0] p += 1; // p == &a[1] - // FIXME: This is a known problem with -Wpointer-arith (https://github.com/llvm/llvm-project/issues/28328) - int d = p - a; // d == 1 // expected-warning{{subtraction of pointers to type 'int[m]' of zero size has undefined behavior}} + int d = p - a; // d == 1 - // FIXME: This is a known problem with -Wpointer-arith (https://github.com/llvm/llvm-project/issues/28328) - d = &(a[2]) - &(a[1]); // expected-warning{{subtraction of pointers to type 'int[m]' of zero size has undefined behavior}} + d = &(a[2]) - &(a[1]); d = a[2] - a[1]; // expected-warning{{Subtraction of two pointers that}} } diff --git a/clang/test/Sema/empty1.c b/clang/test/Sema/empty1.c index 6c5fe76833f3f..0d483bed4fc72 100644 --- a/clang/test/Sema/empty1.c +++ b/clang/test/Sema/empty1.c @@ -85,3 +85,28 @@ int func_9(struct emp_1 (*x)[], struct emp_1 (*y)[]) { int func_10(int (*x)[0], int (*y)[0]) { return x - y; // expected-warning {{subtraction of pointers to type 'int[0]' of zero size has undefined behavior}} } + +// A variably modified type is modelled as having zero size because its size is +// not known statically. It is not an empty type, so it must not be diagnosed. +int func_11(int n) { + int v[n]; + return &v + 1 - &v; +} + +// Still provably zero-sized: zero-sized base element or a zero constant dimension. +int func_12(int n) { + struct emp_1 v[n]; + return &v + 1 - &v; // expected-warning {{subtraction of pointers to type 'struct emp_1[n]' of zero size has undefined behavior}} +} + +int func_13(int n) { + int v[n][0]; + return &v + 1 - &v; // expected-warning {{subtraction of pointers to type 'int[n][0]' of zero size has undefined behavior}} +} + +// A variable bound that folds to a nonzero constant is not zero-sized. +int func_14(void) { + const int four = 4; + int v[four]; + return &v + 1 - &v; +} diff --git a/clang/test/SemaCXX/pointer-sub-zero-size.cpp b/clang/test/SemaCXX/pointer-sub-zero-size.cpp new file mode 100644 index 0000000000000..f90a424143b5e --- /dev/null +++ b/clang/test/SemaCXX/pointer-sub-zero-size.cpp @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++17 %s + +// GH28328: a dependent array bound is not diagnosed in the template pattern; +// the check runs against the instantiated type. +template <int N> +int not_instantiated() { + int array[N]; + return &array - &array; +} + +template <int N> +int instantiated() { + int array[N]; + return &array - &array; // expected-warning {{subtraction of pointers to type 'int[0]' of zero size has undefined behavior}} +} + +int x = instantiated<0>(); // expected-note {{in instantiation of function template specialization 'instantiated<0>' requested here}} +int y = instantiated<1>(); _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
