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 ee24ac00d8.
This commit is contained in:
parent
eecd874fba
commit
04aa50715c
4 changed files with 3 additions and 95 deletions
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
// CHECK: call void %
|
||||
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();
|
||||
}
|
||||
|
||||
struct B {
|
||||
|
|
|
|||
|
|
@ -10309,7 +10309,7 @@
|
|||
<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>
|
||||
|
|
|
|||
Loading…
Reference in a new issue