Skip to content

Commit 6e708e7

Browse files
zmodemdyung
authored andcommitted
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 ee24ac0. (cherry picked from commit 04aa507)
1 parent 5100381 commit 6e708e7

4 files changed

Lines changed: 3 additions & 95 deletions

File tree

clang/lib/AST/DeclCXX.cpp

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2600,41 +2600,6 @@ CXXMethodDecl *CXXMethodDecl::getDevirtualizedMethod(const Expr *Base,
26002600
}
26012601
}
26022602

2603-
// By CWG1504 / C++11 [expr.add]p6, pointer arithmetic on a base pointer into
2604-
// an array of derived objects is undefined behavior when the element type and
2605-
// pointee type are not similar. This means we can devirtualize calls on
2606-
// objects accessed through array subscripts or pointer arithmetic with
2607-
// non-zero offsets, since the dynamic type must match the static type.
2608-
//
2609-
// A single object is considered to be an array of one element, so p[0]
2610-
// could still be a derived object, but p[N] for N != 0 cannot.
2611-
const Expr *Inner = Base->IgnoreParenImpCasts();
2612-
if (const auto *UO = dyn_cast<UnaryOperator>(Inner))
2613-
if (UO->getOpcode() == UO_Deref)
2614-
Inner = UO->getSubExpr()->IgnoreParenImpCasts();
2615-
2616-
// Handle p[N].f() (dot syntax with array subscript).
2617-
if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(Inner)) {
2618-
Expr::EvalResult Result;
2619-
if (ASE->getIdx()->EvaluateAsInt(Result, getASTContext()) &&
2620-
!Result.Val.getInt().isZero())
2621-
return DevirtualizedMethod;
2622-
}
2623-
2624-
// Handle (p + N)->f() (arrow syntax with pointer arithmetic).
2625-
if (const auto *BO = dyn_cast<BinaryOperator>(Inner)) {
2626-
if (BO->getOpcode() == BO_Add || BO->getOpcode() == BO_Sub) {
2627-
// Identify the integer operand (the offset).
2628-
const Expr *IdxExpr = BO->getLHS()->getType()->isPointerType()
2629-
? BO->getRHS()
2630-
: BO->getLHS();
2631-
Expr::EvalResult Result;
2632-
if (IdxExpr->EvaluateAsInt(Result, getASTContext()) &&
2633-
!Result.Val.getInt().isZero())
2634-
return DevirtualizedMethod;
2635-
}
2636-
}
2637-
26382603
// We can't devirtualize the call.
26392604
return nullptr;
26402605
}

clang/test/CXX/drs/cwg15xx.cpp

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,25 +11,6 @@
1111
// cxx98-error@-1 {{variadic macros are a C99 feature}}
1212
#endif
1313

14-
namespace cwg1504 { // cwg1504: 23
15-
#if __cplusplus >= 201103L
16-
// CWG1504: Pointer arithmetic after derived-base conversion
17-
struct Base { int x; };
18-
struct Derived : Base { int y; };
19-
constexpr Derived arr[2] = {};
20-
21-
// Pointer arithmetic on a base pointer into a derived array is UB,
22-
// and the constexpr evaluator must diagnose it.
23-
constexpr int test(int n) {
24-
return ((const Base*)arr)[n].x; // #cwg1504-x
25-
}
26-
constexpr int bad = test(1);
27-
// since-cxx11-error@-1 {{constexpr variable 'bad' must be initialized by a constant expression}}
28-
// since-cxx11-note@#cwg1504-x {{cannot access field of pointer past the end of object}}
29-
// since-cxx11-note@-3 {{in call to 'test(1)'}}
30-
#endif
31-
} // namespace cwg1504
32-
3314
namespace cwg1512 { // cwg1512: 4
3415
void f(char *p) {
3516
if (p > 0) {}

clang/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp

Lines changed: 2 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -92,48 +92,10 @@ void fd(D d, XD xd, D *p) {
9292
// CHECK: call void %
9393
p[0].f();
9494

95-
// We can devirtualize this, by CWG1504 / [expr.add]/6 (if the array
95+
// FIXME: We can devirtualize this, by C++1z [expr.add]/6 (if the array
9696
// element type and the pointee type are not similar, behavior is undefined).
97-
// CHECK: call void @_ZN1A1fEv
98-
p[1].f();
99-
100-
// Negative indices are also UB for the same reason.
101-
// CHECK: call void @_ZN1A1fEv
102-
p[-1].f();
103-
104-
// Pointer arithmetic with arrow syntax: (p + N)->f()
105-
// CHECK: call void @_ZN1A1fEv
106-
(p + 1)->f();
107-
108-
// Pointer subtraction with arrow syntax: (p - N)->f()
109-
// CHECK: call void @_ZN1A1fEv
110-
(p - 1)->f();
111-
112-
// Can't devirtualize with non-constant index; we can't prove N != 0.
113-
int n = 1;
114-
// CHECK: call void %
115-
p[n].f();
116-
117-
// Zero through expression: p[1-1] evaluates to 0, can't devirtualize.
118-
// CHECK: call void %
119-
p[1-1].f();
120-
121-
// (p + 0)->f() also can't be devirtualized (same as *p).
12297
// CHECK: call void %
123-
(p + 0)->f();
124-
125-
// 1 + p is legal pointer arithmetic too.
126-
// CHECK: call void @_ZN1A1fEv
127-
(1 + p)->f();
128-
129-
// Constant variables are evaluated.
130-
const int N = 1;
131-
// CHECK: call void @_ZN1A1fEv
132-
p[N].f();
133-
134-
// Pointer arithmetic with deref: *(p + 1)
135-
// CHECK: call void @_ZN1A1fEv
136-
(*(p + 1)).f();
98+
p[1].f();
13799
}
138100

139101
struct B {

clang/www/cxx_dr_status.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10309,7 +10309,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
1030910309
<td>[<a href="https://wg21.link/expr.add">expr.add</a>]</td>
1031010310
<td>CD3</td>
1031110311
<td>Pointer arithmetic after derived-base conversion</td>
10312-
<td class="full" align="center">Clang 23</td>
10312+
<td class="unknown" align="center">Unknown</td>
1031310313
</tr>
1031410314
<tr id="1505">
1031510315
<td><a href="https://cplusplus.github.io/CWG/issues/1505.html">1505</a></td>

0 commit comments

Comments
 (0)