Skip to content

Commit

Permalink
[clang] Avoid triggering vtable instantiation for C++23 constexpr dtor (
Browse files Browse the repository at this point in the history
llvm#102605)

In C++23 anything can be constexpr, including a dtor of a class whose
members and bases don't have constexpr dtors. Avoid early triggering of
vtable instantiation int this case.

Fixes llvm#102293

(cherry picked from commit d469794)
  • Loading branch information
Fznamznon authored and llvmbot committed Aug 12, 2024
1 parent 4fd6b32 commit d6beb48
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 1 deletion.
29 changes: 28 additions & 1 deletion clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7042,11 +7042,38 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) {
}
}

bool EffectivelyConstexprDestructor = true;
// Avoid triggering vtable instantiation due to a dtor that is not
// "effectively constexpr" for better compatibility.
// See https://github.com/llvm/llvm-project/issues/102293 for more info.
if (isa<CXXDestructorDecl>(M)) {
auto Check = [](QualType T, auto &&Check) -> bool {
const CXXRecordDecl *RD =
T->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
if (!RD || !RD->isCompleteDefinition())
return true;

if (!RD->hasConstexprDestructor())
return false;

for (const CXXBaseSpecifier &B : RD->bases())
if (!Check(B.getType(), Check))
return false;
for (const FieldDecl *FD : RD->fields())
if (!Check(FD->getType(), Check))
return false;
return true;
};
EffectivelyConstexprDestructor =
Check(QualType(Record->getTypeForDecl(), 0), Check);
}

// Define defaulted constexpr virtual functions that override a base class
// function right away.
// FIXME: We can defer doing this until the vtable is marked as used.
if (CSM != CXXSpecialMemberKind::Invalid && !M->isDeleted() &&
M->isDefaulted() && M->isConstexpr() && M->size_overridden_methods())
M->isDefaulted() && M->isConstexpr() && M->size_overridden_methods() &&
EffectivelyConstexprDestructor)
DefineDefaultedFunction(*this, M, M->getLocation());

if (!Incomplete)
Expand Down
22 changes: 22 additions & 0 deletions clang/test/SemaCXX/gh102293.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// RUN: %clang_cc1 -std=c++23 -fsyntax-only -verify %s
// expected-no-diagnostics

template <typename T> static void destroy() {
T t;
++t;
}

struct Incomplete;

template <typename = int> struct HasD {
~HasD() { destroy<Incomplete*>(); }
};

struct HasVT {
virtual ~HasVT();
};

struct S : HasVT {
HasD<> v;
};

0 comments on commit d6beb48

Please sign in to comment.