[clang] [Clang]Preserve array information when reconstructing LValues (#223064) (PR #230599)

Aditya Roy Chowdhury via cfe-commits cfe-commits at lists.llvm.org
Sun Oct 25 05:36:33 PDT 2026


https://github.com/adiroy28852 updated https://github.com/llvm/llvm-project/pull/230599

>From 46ddf7e600e677652bed7de2b1404ef1c754ef0b Mon Sep 17 00:00:00 2001
From: Aditya Roy Chowdhury <adityaroy2.ar.ar at gmail.com>
Date: Fri, 9 Oct 2026 22:17:40 +0530
Subject: [PATCH 1/3] updated condition for reconstructed LValue information
 (#223064)

---
 clang/lib/AST/ExprConstant.cpp                |  4 ---
 .../SemaCXX/constant-expression-cxx2a.cpp     | 29 +++++++++++++++++++
 2 files changed, 29 insertions(+), 4 deletions(-)

diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 34c3e39807c7f1..63fdb508a24675 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -208,10 +208,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-cxx2a.cpp b/clang/test/SemaCXX/constant-expression-cxx2a.cpp
index 870865646a61e2..b9816f074c3cc6 100644
--- a/clang/test/SemaCXX/constant-expression-cxx2a.cpp
+++ b/clang/test/SemaCXX/constant-expression-cxx2a.cpp
@@ -1544,3 +1544,32 @@ namespace GH197403 {
   }
   static_assert(test() == 0);
 }
+
+namespace GH223064 {
+  struct A {
+    int n;
+  };
+  struct B : A {} b[2];
+
+  constexpr int *base_array_element() {
+    A *p = b;
+    return &static_cast<B *>(p)[1].n;
+  }
+  static_assert(base_array_element() == &b[1].n);
+
+  struct Padding {
+    int pad;
+  };
+  struct C : Padding, B {} c[2];
+
+  constexpr int *indirect_nonfirst_base_array_element() {
+    A *p = c;
+    return &static_cast<C *>(p)[1].n;
+  }
+  static_assert(indirect_nonfirst_base_array_element() == &c[1].n);
+
+  constexpr int *out_of_bounds(A *p) {
+    return &static_cast<B *>(p)[2].n; // expected-note {{cannot access base class of pointer past the end of object}}
+  }
+  static_assert(out_of_bounds(b) == nullptr); // expected-error {{static assertion is not an integral constant expression}} \ expected-note {{in call to 'out_of_bounds(&b[0])'}}
+}

>From 51ab7945fb8df9b50fe1fc6d3a0e222277affec1 Mon Sep 17 00:00:00 2001
From: Aditya Roy Chowdhury <adityaroy2.ar.ar at gmail.com>
Date: Sun, 25 Oct 2026 09:56:53 +0530
Subject: [PATCH 2/3] [Clang][ConstantExpr] Preserve array metadata for base
 subobjects

---
 clang/lib/AST/ExprConstant.cpp                | 12 ++++++---
 .../SemaCXX/constant-expression-cxx2a.cpp     | 25 ++++++++++++++++++-
 2 files changed, 32 insertions(+), 5 deletions(-)

diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 63fdb508a24675..d2428777713593 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -208,6 +208,9 @@ namespace {
         ArraySize = 0;
         MostDerivedLength = I + 1;
         IsArray = false;
+      } else {
+        // Path[I] describes a base class. The base is part of the current
+        // most-derived object, so preserve its array information.
       }
     }
     return MostDerivedLength;
@@ -4596,10 +4599,11 @@ static bool AreElementsOfSameArray(QualType ObjType,
   if (A.Entries.size() != B.Entries.size())
     return false;
 
-  bool IsArray = A.MostDerivedIsArrayElement;
-  if (IsArray && A.MostDerivedPathLength != A.Entries.size())
-    // A is a subobject of the array element.
-    return false;
+  // A base-class subobject of an array element is not itself an element of
+  // that array. Treat it as a non-array object, while retaining the array
+  // information for casts back to the most-derived type.
+  bool IsArray = A.MostDerivedIsArrayElement &&
+                 A.MostDerivedPathLength == A.Entries.size();
 
   // If A (and B) designates an array element, the last entry will be the array
   // index. That doesn't have to match. Otherwise, we're in the 'implicit array
diff --git a/clang/test/SemaCXX/constant-expression-cxx2a.cpp b/clang/test/SemaCXX/constant-expression-cxx2a.cpp
index b9816f074c3cc6..dcfd7d5c5ed131 100644
--- a/clang/test/SemaCXX/constant-expression-cxx2a.cpp
+++ b/clang/test/SemaCXX/constant-expression-cxx2a.cpp
@@ -1557,6 +1557,12 @@ namespace GH223064 {
   }
   static_assert(base_array_element() == &b[1].n);
 
+  constexpr int pointer_difference() {
+    A *p = b;
+    return p - p;
+  }
+  static_assert(pointer_difference() == 0);
+
   struct Padding {
     int pad;
   };
@@ -1568,8 +1574,25 @@ namespace GH223064 {
   }
   static_assert(indirect_nonfirst_base_array_element() == &c[1].n);
 
+  struct MemberArray {
+    B item[2];
+  } member[2];
+  constexpr int *member_array_element() {
+    A *p = member[0].item;
+    return &static_cast<B *>(p)[1].n;
+  }
+  static_assert(member_array_element() == &member[0].item[1].n);
+
+  B nested[2][2];
+  constexpr int *nested_array_element() {
+    A *p = nested[0];
+    return &static_cast<B *>(p)[1].n;
+  }
+  static_assert(nested_array_element() == &nested[0][1].n);
+
   constexpr int *out_of_bounds(A *p) {
     return &static_cast<B *>(p)[2].n; // expected-note {{cannot access base class of pointer past the end of object}}
   }
-  static_assert(out_of_bounds(b) == nullptr); // expected-error {{static assertion is not an integral constant expression}} \ expected-note {{in call to 'out_of_bounds(&b[0])'}}
+  static_assert(out_of_bounds(b) == nullptr); // expected-error {{static assertion expression is not an integral constant expression}} \
+                                              // expected-note {{in call to 'out_of_bounds(&b[0])'}}
 }

>From fc63e45059a1b1afe013ce993ba7b20a7bec9eaa Mon Sep 17 00:00:00 2001
From: Aditya Roy Chowdhury <adityaroy2.ar.ar at gmail.com>
Date: Sun, 25 Oct 2026 18:00:07 +0530
Subject: [PATCH 3/3] [Clang][ConstantExpr] Test base-object pointer
 subtraction

---
 clang/test/SemaCXX/constant-expression-cxx2a.cpp | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/clang/test/SemaCXX/constant-expression-cxx2a.cpp b/clang/test/SemaCXX/constant-expression-cxx2a.cpp
index dcfd7d5c5ed131..2cf030be614129 100644
--- a/clang/test/SemaCXX/constant-expression-cxx2a.cpp
+++ b/clang/test/SemaCXX/constant-expression-cxx2a.cpp
@@ -1563,6 +1563,9 @@ namespace GH223064 {
   }
   static_assert(pointer_difference() == 0);
 
+  constexpr auto difference(A *p, A *q) { return p - q; }
+  static_assert(difference(&b[1], &b[0]) == 1);
+
   struct Padding {
     int pad;
   };



More information about the cfe-commits mailing list