Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion clang/lib/AST/DeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 operators redecl chain to find the one that belongs
// Walk the call operator's redecl chain to find the one that belongs
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unrelated change.

// to this module.
//
// TODO: We need to fix this properly (see
Expand Down Expand Up @@ -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]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see the 'beyond [0]' in that standardeeze, can you better clarify it?

Also, where are you checking for >0 here? It seems like you'd do this in every case? What is making this skip the 0 case?

// 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)
Expand Down
6 changes: 3 additions & 3 deletions clang/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't get the comment on 89: Why can we virtualize this but not that one?

// are not similar, behavior is undefined).
// CHECK: call void @_ZN1D1fEv
p[1].f();
}

Expand Down
Loading