https://github.com/flash1729 updated https://github.com/llvm/llvm-project/pull/217465
>From 5adb6f1e3cd8c159f745c99251a07948c3b03879 Mon Sep 17 00:00:00 2001 From: flash1729 <[email protected]> Date: Mon, 17 Aug 2026 06:20:57 +0530 Subject: [PATCH] [clang][Sema] Don't report pointer subtraction on a VLA as zero size 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 variable bounds as integer constant expressions, and warn only when a dimension is provably zero or the base element type has zero size. This keeps the warning for genuinely zero-sized cases such as int[0], zero-sized structs, and VLAs of zero-sized types, while dropping it when the size is simply unknown. Fixes #28328 --- clang/docs/ReleaseNotes.md | 6 ++++++ clang/lib/Sema/SemaExpr.cpp | 36 +++++++++++++++++++++++++------ clang/test/Analysis/pointer-sub.c | 6 ++---- clang/test/Sema/empty1.c | 26 ++++++++++++++++++++++ 4 files changed, 63 insertions(+), 11 deletions(-) diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index 3c6694f510952..1ebd73125347e 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -416,6 +416,12 @@ features cannot lower the translation-unit ABI level; - `-Wc++98-compat` now diagnoses explicit conversion functions in C++20 and later, matching the behavior in C++11 through C++17. (#GH161689) +- `-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 da76bbf3c35f0..aa1f5cc294d48 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -11781,6 +11781,29 @@ QualType Sema::CheckAdditionOperands(ExprResult &LHS, ExprResult &RHS, return PExp->getType(); } +/// Determine whether the size of \p T is provably zero, so that pointer +/// subtraction over it can be diagnosed as dividing by a zero element size. +/// The total size of an array is the product of its dimensions and the size +/// of its base element, so it is provably zero if any dimension is provably +/// zero or the base element has zero size. A variable dimension whose bound +/// does not fold to an integer constant is assumed to be 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, @@ -11915,15 +11938,14 @@ 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) + // case subtraction does not make sense. A variably modified type is + // modelled as having zero size, but its size is generally only known + // at run time, so 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..6cd05dae1fed5 100644 --- a/clang/test/Sema/empty1.c +++ b/clang/test/Sema/empty1.c @@ -85,3 +85,29 @@ 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; +} + +// But an array with a variable dimension is still provably zero-sized when its +// base element is zero-sized or one of its constant dimensions is zero. +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; +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
