https://github.com/dyung updated https://github.com/llvm/llvm-project/pull/209613
>From a81c82c64917d19824769f64c1ea2f76e4c8694e Mon Sep 17 00:00:00 2001 From: Hans Wennborg <[email protected]> Date: Tue, 14 Jul 2026 22:10:27 +0200 Subject: [PATCH] Revert "[Clang] Allow devirtualization involving array subscripts with constant indices when the pointee type is known [CWG1504] (#207540) (#209596) It caused miscompiles, see discussion on the PR. This reverts commit ee24ac00d874ce82eaf36431f9aeb2ad744bc3b8. (cherry picked from commit 04aa50715cafa5f205b44bc88a6f721d296ec91c) --- clang/lib/AST/DeclCXX.cpp | 35 ---------------- clang/test/CXX/drs/cwg15xx.cpp | 19 --------- .../devirtualize-virtual-function-calls.cpp | 42 +------------------ clang/www/cxx_dr_status.html | 2 +- 4 files changed, 3 insertions(+), 95 deletions(-) diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index ef7e58536202b..0573cdf95952a 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -2600,41 +2600,6 @@ CXXMethodDecl *CXXMethodDecl::getDevirtualizedMethod(const Expr *Base, } } - // By CWG1504 / C++11 [expr.add]p6, pointer arithmetic on a base pointer into - // an array of derived objects is undefined behavior when the element type and - // pointee type are not similar. This means we can devirtualize calls on - // objects accessed through array subscripts or pointer arithmetic with - // non-zero offsets, since the dynamic type must match the static type. - // - // 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. - const Expr *Inner = Base->IgnoreParenImpCasts(); - if (const auto *UO = dyn_cast<UnaryOperator>(Inner)) - if (UO->getOpcode() == UO_Deref) - Inner = UO->getSubExpr()->IgnoreParenImpCasts(); - - // Handle p[N].f() (dot syntax with array subscript). - if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(Inner)) { - Expr::EvalResult Result; - if (ASE->getIdx()->EvaluateAsInt(Result, getASTContext()) && - !Result.Val.getInt().isZero()) - return DevirtualizedMethod; - } - - // Handle (p + N)->f() (arrow syntax with pointer arithmetic). - if (const auto *BO = dyn_cast<BinaryOperator>(Inner)) { - if (BO->getOpcode() == BO_Add || BO->getOpcode() == BO_Sub) { - // Identify the integer operand (the offset). - const Expr *IdxExpr = BO->getLHS()->getType()->isPointerType() - ? BO->getRHS() - : BO->getLHS(); - Expr::EvalResult Result; - if (IdxExpr->EvaluateAsInt(Result, getASTContext()) && - !Result.Val.getInt().isZero()) - 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 53f262740eae2..5a9b80ed028c4 100644 --- a/clang/test/CXX/drs/cwg15xx.cpp +++ b/clang/test/CXX/drs/cwg15xx.cpp @@ -11,25 +11,6 @@ // cxx98-error@-1 {{variadic macros are a C99 feature}} #endif -namespace cwg1504 { // cwg1504: 23 -#if __cplusplus >= 201103L - // 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; // #cwg1504-x - } - constexpr int bad = test(1); - // since-cxx11-error@-1 {{constexpr variable 'bad' must be initialized by a constant expression}} - // since-cxx11-note@#cwg1504-x {{cannot access field of pointer past the end of object}} - // since-cxx11-note@-3 {{in call to 'test(1)'}} -#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 32a887e8fbcc9..b50881db63e05 100644 --- a/clang/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp +++ b/clang/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp @@ -92,48 +92,10 @@ void fd(D d, XD xd, D *p) { // CHECK: call void % p[0].f(); - // We can devirtualize this, by CWG1504 / [expr.add]/6 (if the array + // FIXME: We can devirtualize this, by C++1z [expr.add]/6 (if the array // element type and the pointee type are not similar, behavior is undefined). - // CHECK: call void @_ZN1A1fEv - p[1].f(); - - // Negative indices are also UB for the same reason. - // CHECK: call void @_ZN1A1fEv - p[-1].f(); - - // Pointer arithmetic with arrow syntax: (p + N)->f() - // CHECK: call void @_ZN1A1fEv - (p + 1)->f(); - - // Pointer subtraction with arrow syntax: (p - N)->f() - // CHECK: call void @_ZN1A1fEv - (p - 1)->f(); - - // Can't devirtualize with non-constant index; we can't prove N != 0. - int n = 1; - // CHECK: call void % - p[n].f(); - - // Zero through expression: p[1-1] evaluates to 0, can't devirtualize. - // CHECK: call void % - p[1-1].f(); - - // (p + 0)->f() also can't be devirtualized (same as *p). // CHECK: call void % - (p + 0)->f(); - - // 1 + p is legal pointer arithmetic too. - // CHECK: call void @_ZN1A1fEv - (1 + p)->f(); - - // Constant variables are evaluated. - const int N = 1; - // CHECK: call void @_ZN1A1fEv - p[N].f(); - - // Pointer arithmetic with deref: *(p + 1) - // CHECK: call void @_ZN1A1fEv - (*(p + 1)).f(); + p[1].f(); } struct B { diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html index 73c8be98e7848..af91ac559d274 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="full" align="center">Clang 23</td> + <td class="unknown" align="center">Unknown</td> </tr> <tr id="1505"> <td><a href="https://cplusplus.github.io/CWG/issues/1505.html">1505</a></td> _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
