https://github.com/AZero13 updated 
https://github.com/llvm/llvm-project/pull/207540

>From 876f27159f4bdab88d8a94914da91600d4dfd119 Mon Sep 17 00:00:00 2001
From: AZero13 <[email protected]>
Date: Sat, 4 Jul 2026 16:41:32 -0400
Subject: [PATCH] [Clang] Allow devirtualization involving array subscripts
 with constant indices when the pointee type is known

By C++1z [expr.add]/6, if the array element type and the pointee type are not 
similar, behavior is undefined.
---
 clang/docs/ReleaseNotes.md                    |  6 +++++
 clang/lib/AST/DeclCXX.cpp                     | 14 +++++++++++
 clang/test/CXX/drs/cwg15xx.cpp                | 24 +++++++++++++++++++
 .../devirtualize-virtual-function-calls.cpp   |  4 ++--
 clang/www/cxx_dr_status.html                  |  2 +-
 5 files changed, 47 insertions(+), 3 deletions(-)

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index bbd42848a98c2..fedaeebf76520 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -275,6 +275,9 @@ latest release, please see the [Clang Web 
Site](https://clang.llvm.org) or the
 
 #### Resolutions to C++ Defect Reports
 
+- Clang now implements 
[CWG1504](https://cplusplus.github.io/CWG/issues/1504.html)
+  which makes pointer arithmetic after derived-base conversion undefined 
behavior,
+  allowing devirtualization of calls through non-zero array subscripts.
 - Implemented [CWG1780 Explicit instantiation/specialization of generic lambda
   operator()](https://cplusplus.github.io/CWG/issues/1780.html)
 - Clang now allows omitting `typename` before a template name in a
@@ -323,6 +326,9 @@ latest release, please see the [Clang Web 
Site](https://clang.llvm.org) or the
 
 ### Non-comprehensive list of changes in this release
 
+- Clang can now devirtualize virtual function calls on objects accessed through
+  array subscript expressions with non-zero constant indices, based on the
+  resolution of [CWG1504](https://cplusplus.github.io/CWG/issues/1504.html).
 - Added support for floating point and pointer values in most `__atomic_`
   builtins.
 - Added `__builtin_stdc_rotate_left` and `__builtin_stdc_rotate_right`
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 0573cdf95952a..19755ac824fc7 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -2600,6 +2600,20 @@ CXXMethodDecl 
*CXXMethodDecl::getDevirtualizedMethod(const Expr *Base,
     }
   }
 
+  // We can devirtualize calls on an object accessed by an array subscript
+  // expression with a non-zero index. A pointer to the base of an array must
+  // point to an object of the array element type, so the dynamic type of the
+  // element can't be a derived class. A single object is considered to be an
+  // array of one element, so p[0] could still be a derived object, but p[N]
+  // for N != 0 cannot.
+  if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(Base)) {
+    Expr::EvalResult Result;
+    if (ASE->getIdx()->EvaluateAsInt(Result, getASTContext())) {
+      if (Result.Val.getInt() != 0)
+        return DevirtualizedMethod;
+    }
+  }
+
   // We can't devirtualize the call.
   return nullptr;
 }
diff --git a/clang/test/CXX/drs/cwg15xx.cpp b/clang/test/CXX/drs/cwg15xx.cpp
index 5a9b80ed028c4..158152b7fd461 100644
--- a/clang/test/CXX/drs/cwg15xx.cpp
+++ b/clang/test/CXX/drs/cwg15xx.cpp
@@ -11,6 +11,30 @@
 // cxx98-error@-1 {{variadic macros are a C99 feature}}
 #endif
 
+namespace cwg1504 { // cwg1504: 23
+  // CWG1504: Pointer arithmetic after derived-base conversion
+#if __cplusplus >= 201402L
+  struct Base {
+    int x;
+  };
+  struct Derived : Base {
+    int y;
+  };
+
+  // Pointer arithmetic on a base pointer into a derived array is UB,
+  // and the constexpr evaluator must diagnose it.
+  constexpr int test_nonzero() {
+    Derived arr[2] = {};
+    const Base *p = arr;
+    return p[1].x;
+    // since-cxx11-note@-1 {{cannot access field of pointer past the end of 
object}}
+  }
+  constexpr int bad = test_nonzero();
+  // since-cxx11-error@-1 {{constexpr variable 'bad' must be initialized by a 
constant expression}}
+  // since-cxx11-note@-2 {{in call to}}
+#endif
+} // namespace cwg1504
+
 namespace cwg1512 { // cwg1512: 4
   void f(char *p) {
     if (p > 0) {}
diff --git a/clang/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp 
b/clang/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp
index b50881db63e05..47eefd310aeb1 100644
--- a/clang/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp
+++ b/clang/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp
@@ -92,9 +92,9 @@ void fd(D d, XD xd, D *p) {
   // CHECK: call void %
   p[0].f();
 
-  // FIXME: We can devirtualize this, by C++1z [expr.add]/6 (if the array
+  // We can devirtualize this, by CWG1504 / [expr.add]/6 (if the array
   // element type and the pointee type are not similar, behavior is undefined).
-  // CHECK: call void %
+  // CHECK: call void @_ZN1A1fEv
   p[1].f();
 }
 
diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html
index af91ac559d274..73c8be98e7848 100755
--- a/clang/www/cxx_dr_status.html
+++ b/clang/www/cxx_dr_status.html
@@ -10309,7 +10309,7 @@ <h2 id="cxxdr">C++ defect report implementation 
status</h2>
     <td>[<a href="https://wg21.link/expr.add";>expr.add</a>]</td>
     <td>CD3</td>
     <td>Pointer arithmetic after derived-base conversion</td>
-    <td class="unknown" align="center">Unknown</td>
+    <td class="full" align="center">Clang 23</td>
   </tr>
   <tr id="1505">
     <td><a 
href="https://cplusplus.github.io/CWG/issues/1505.html";>1505</a></td>

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to