https://github.com/anandkvinu updated https://github.com/llvm/llvm-project/pull/223184
>From 74fa096819b826be252610c21e38458a2925f555 Mon Sep 17 00:00:00 2001 From: Anand K Vinu <[email protected]> Date: Sun, 13 Sep 2026 02:16:52 +0530 Subject: [PATCH 1/2] [Clang][Sema] Preserve most derived array info across base class path entries, Add regression tests for primary and non primary base subobjects. format using git clang-format --- clang/lib/AST/ExprConstant.cpp | 4 - .../SemaCXX/constant-expression-cxx1z.cpp | 83 +++++++++++++++++++ 2 files changed, 83 insertions(+), 4 deletions(-) diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 1286c77ad1c69..00568d1d029e3 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -235,10 +235,6 @@ namespace { ArraySize = 0; MostDerivedLength = I + 1; IsArray = false; - } else { - // Path[I] describes a base class. - ArraySize = 0; - IsArray = false; } } return MostDerivedLength; diff --git a/clang/test/SemaCXX/constant-expression-cxx1z.cpp b/clang/test/SemaCXX/constant-expression-cxx1z.cpp index c0766f70cf881..f985065009a19 100644 --- a/clang/test/SemaCXX/constant-expression-cxx1z.cpp +++ b/clang/test/SemaCXX/constant-expression-cxx1z.cpp @@ -178,6 +178,89 @@ namespace LambdaCallOp { } } +// Regression tests for https://github.com/llvm/llvm-project/issues/223064 +// +// The constant evaluator loses track of an lvalue's most-derived array +// information when an APValue containing a base-class path entry is +// reconstructed into an LValue/SubobjectDesignator. A base-class path +// entry does not advance the most-derived path length, so it must not +// clobber the most-derived array size/flag either; those fields belong +// to the entry at MostDerivedPathLength, not to whatever entry was +// processed last. +namespace GH223064 { + +// Original reproducer: + +namespace BasicBaseSubobject { + struct A { int n; }; + struct B : A {} b[2]; + + constexpr int *f() { + A *p = b; + return &static_cast<B*>(p)[1].n; + } + static_assert(f() == &b[1].n, ""); +} + +// Same shape, but through the second of two non-virtual bases, so the +// base subobject sits at a non-zero offset within the derived object. +namespace NonPrimaryBase { + struct A { int n; }; + struct A2 { int m; }; + struct B : A, A2 {} b[2]; + + constexpr int *f() { + A2 *p = &b[0]; + return &static_cast<B*>(p)[1].m; + } + static_assert(f() == &b[1].m, ""); +} + +// Two trailing base-class path entries in a row (C -> B -> A), rather than +// just one +namespace MultipleTrailingBaseEntries { + struct A { int n; }; + struct B : A {}; + struct C : B {} c[2]; + + constexpr int *f() { + A *p = &c[0]; + return &static_cast<C*>(p)[1].n; + } + static_assert(f() == &c[1].n, ""); +} + +// Pointer arithmetic performed directly on the downcast pointer, rather +// than array subscripting, must also see the correct bounds. +namespace ArithmeticOnDowncastPointer { + struct A { int n; }; + struct B : A {} b[3]; + + constexpr int *f() { + A *p = b; + B *q = static_cast<B*>(p) + 2; + return &q->n; + } + static_assert(f() == &b[2].n, ""); +} + +// indexing +// past the end of the array through the same base-subobject pattern +// should still be rejected. +namespace OutOfBoundsStillRejected { + struct A { int n; }; + struct B : A {} b[2]; + + constexpr int *f(int i) { + A *p = b; + return &static_cast<B*>(p)[i].n; // expected-note {{cannot refer to element 5 of array of 2 elements in a constant expression}} + } + static_assert(f(5) == nullptr, ""); // expected-error {{not an integral constant expression}} \ + // expected-note {{in call to 'f(5)'}} +} + +} // namespace GH223064 + // This used to crash due to an assertion failure, // see gh#67690 namespace { >From 92e4d3d25f8b3111afb1fd4e1ebe2cdd959a19bb Mon Sep 17 00:00:00 2001 From: "Anand.k.vinu" <[email protected]> Date: Mon, 14 Sep 2026 13:16:10 +0530 Subject: [PATCH 2/2] Update clang/test/SemaCXX/constant-expression-cxx1z.cpp Co-authored-by: Lakshay Chauhan <[email protected]> --- clang/test/SemaCXX/constant-expression-cxx1z.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/SemaCXX/constant-expression-cxx1z.cpp b/clang/test/SemaCXX/constant-expression-cxx1z.cpp index f985065009a19..f31efdbf5798b 100644 --- a/clang/test/SemaCXX/constant-expression-cxx1z.cpp +++ b/clang/test/SemaCXX/constant-expression-cxx1z.cpp @@ -244,7 +244,7 @@ namespace ArithmeticOnDowncastPointer { static_assert(f() == &b[2].n, ""); } -// indexing +// indexing // past the end of the array through the same base-subobject pattern // should still be rejected. namespace OutOfBoundsStillRejected { _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
