Skip to content

Commit 6edb96a

Browse files
committed
[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.
1 parent 257e483 commit 6edb96a

File tree

2 files changed

+25
-4
lines changed

2 files changed

+25
-4
lines changed

clang/lib/AST/DeclCXX.cpp

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1689,7 +1689,7 @@ static NamedDecl* getLambdaCallOperatorHelper(const CXXRecordDecl &RD) {
16891689
// auto L = [](T) { }; // But A's call operator would want A's here.
16901690
// }
16911691
//
1692-
// Walk the call operators redecl chain to find the one that belongs
1692+
// Walk the call operator's redecl chain to find the one that belongs
16931693
// to this module.
16941694
//
16951695
// TODO: We need to fix this properly (see
@@ -2465,6 +2465,27 @@ CXXMethodDecl *CXXMethodDecl::getDevirtualizedMethod(const Expr *Base,
24652465
if (Base->isPRValue() && Base->getType()->isRecordType())
24662466
return this;
24672467

2468+
// Handle array subscripts with constant indices when the pointee type is
2469+
// known
2470+
if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(Base)) {
2471+
QualType BaseTy = ASE->getBase()->getType();
2472+
2473+
// Check if it's a pointer to a record type
2474+
if (BaseTy->isPointerType() && BaseTy->getPointeeType()->isRecordType()) {
2475+
// For C++17 and later, we can devirtualize array access beyond p[0]
2476+
// According to [expr.add]/6, if the array element type and the pointee
2477+
// type are not similar, behavior is undefined, so we can assume they are
2478+
// the same type
2479+
const ASTContext &Context = getParent()->getASTContext();
2480+
const LangOptions &LangOpts = Context.getLangOpts();
2481+
if (LangOpts.CPlusPlus17 &&
2482+
ASE->getIdx()->isIntegerConstantExpr(Context)) {
2483+
// It's a constant index, so it's safe to devirtualize
2484+
return this;
2485+
}
2486+
}
2487+
}
2488+
24682489
// If we don't even know what we would call, we can't devirtualize.
24692490
const CXXRecordDecl *BestDynamicDecl = Base->getBestDynamicClassType();
24702491
if (!BestDynamicDecl)

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

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

95-
// FIXME: We can devirtualize this, by C++1z [expr.add]/6 (if the array
96-
// element type and the pointee type are not similar, behavior is undefined).
97-
// CHECK: call void %
95+
// By C++1z [expr.add]/6 (if the array element type and the pointee type
96+
// are not similar, behavior is undefined).
97+
// CHECK: call void @_ZN1D1fEv
9898
p[1].f();
9999
}
100100

0 commit comments

Comments
 (0)