[clang] [Clang] Allow devirtualization involving array subscripts with constant indices when the pointee type is known (PR #130528)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Mar 10 08:57:26 PDT 2025
https://github.com/AZero13 updated https://github.com/llvm/llvm-project/pull/130528
>From 239617e7733b1f4eb9c9309c2ed16b0cb007df15 Mon Sep 17 00:00:00 2001
From: Rose <gfunni234 at gmail.com>
Date: Sun, 9 Mar 2025 20:05:38 -0400
Subject: [PATCH] [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.
---
clang/lib/AST/DeclCXX.cpp | 23 ++++++++++++++++++-
.../devirtualize-virtual-function-calls.cpp | 6 ++---
2 files changed, 25 insertions(+), 4 deletions(-)
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 7eff776882629..ecba340f0425a 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -1689,7 +1689,7 @@ static NamedDecl* getLambdaCallOperatorHelper(const CXXRecordDecl &RD) {
// auto L = [](T) { }; // But A's call operator would want A's here.
// }
//
- // Walk the call operator’s redecl chain to find the one that belongs
+ // Walk the call operator's redecl chain to find the one that belongs
// to this module.
//
// TODO: We need to fix this properly (see
@@ -2465,6 +2465,27 @@ CXXMethodDecl *CXXMethodDecl::getDevirtualizedMethod(const Expr *Base,
if (Base->isPRValue() && Base->getType()->isRecordType())
return this;
+ // Handle array subscripts with constant indices when the pointee type is known
+ if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(Base)) {
+ QualType BaseTy = ASE->getBase()->getType();
+
+ // Check if it's a pointer to a record type
+ if (BaseTy->isPointerType() &&
+ BaseTy->getPointeeType()->isRecordType()) {
+ // For C++17 and later, we can devirtualize array access beyond p[0]
+ // According to [expr.add]/6, if the array element type and the pointee
+ // type are not similar, behavior is undefined, so we can assume they are
+ // the same type
+ const ASTContext &Context = getParent()->getASTContext();
+ const LangOptions &LangOpts = Context.getLangOpts();
+ if (LangOpts.CPlusPlus17 &&
+ ASE->getIdx()->isIntegerConstantExpr(Context)) {
+ // It's a constant index, so it's safe to devirtualize
+ return this;
+ }
+ }
+ }
+
// If we don't even know what we would call, we can't devirtualize.
const CXXRecordDecl *BestDynamicDecl = Base->getBestDynamicClassType();
if (!BestDynamicDecl)
diff --git a/clang/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp b/clang/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp
index b50881db63e05..44fbe3d27d03a 100644
--- a/clang/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp
+++ b/clang/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp
@@ -92,9 +92,9 @@ void fd(D d, XD xd, D *p) {
// CHECK: call void %
p[0].f();
- // 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 %
+ // By C++1z [expr.add]/6 (if the array element type and the pointee type
+ // are not similar, behavior is undefined).
+ // CHECK: call void @_ZN1D1fEv
p[1].f();
}
More information about the cfe-commits
mailing list