[clang] [Clang] Allow devirtualization involving array subscripts with constant indices when the pointee type is known (PR #207540)
via cfe-commits
cfe-commits at lists.llvm.org
Sat Jul 11 08:25:49 PDT 2026
https://github.com/AZero13 updated https://github.com/llvm/llvm-project/pull/207540
>From 956790562381dadf679c401cfbd0001e18ae27ff Mon Sep 17 00:00:00 2001
From: AZero13 <gfunni234 at gmail.com>
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 | 17 +++++++++++++++++
.../devirtualize-virtual-function-calls.cpp | 4 ++--
clang/www/cxx_dr_status.html | 2 +-
5 files changed, 40 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..1cacf5631f011 100644
--- a/clang/test/CXX/drs/cwg15xx.cpp
+++ b/clang/test/CXX/drs/cwg15xx.cpp
@@ -11,6 +11,23 @@
// cxx98-error at -1 {{variadic macros are a C99 feature}}
#endif
+namespace cwg1504 { // cwg1504: 23
+ // CWG1504: Pointer arithmetic after derived-base conversion
+ struct Base { int x; };
+ struct Derived : Base { int y; };
+ constexpr Derived arr[2] = {};
+
+ // Pointer arithmetic on a base pointer into a derived array is UB,
+ // and the constexpr evaluator must diagnose it.
+ constexpr int test(int n) {
+ return ((const Base*)arr)[n].x;
+ // since-cxx11-note at -1 {{cannot access field of pointer past the end of object}}
+ }
+ constexpr int bad = test(1);
+ // since-cxx11-error at -1 {{constexpr variable 'bad' must be initialized by a constant expression}}
+ // since-cxx11-note at -2 {{in call to 'test(1)'}}
+} // 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>
More information about the cfe-commits
mailing list