[llvm-branch-commits] [clang] release/23.x: Revert "[Clang] Allow devirtualization involving array subscripts with constant indices when the pointee type is known [CWG1504] (#207540) (#209596) (PR #209613)
Douglas Yung via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Wed Jul 15 03:07:33 PDT 2026
https://github.com/dyung updated https://github.com/llvm/llvm-project/pull/209613
>From 6e708e7d66bb2c8daee1334068190c3138ca20ee Mon Sep 17 00:00:00 2001
From: Hans Wennborg <hans at hanshq.net>
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 at -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 at -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 at -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>
More information about the llvm-branch-commits
mailing list