@@ -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 operator’ s 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)
0 commit comments