[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:58:03 PDT 2025


https://github.com/AZero13 updated https://github.com/llvm/llvm-project/pull/130528

>From 6edb96aeb19db0cae71ce35481eb7c009b94cb3b 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..b0f078255594c 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