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
