Skip to content

Commit d469794

Browse files
authored
[clang] Avoid triggering vtable instantiation for C++23 constexpr dtor (#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 #102293
1 parent 7389545 commit d469794

File tree

2 files changed

+50
-1
lines changed

2 files changed

+50
-1
lines changed

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7042,11 +7042,38 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) {
70427042
}
70437043
}
70447044

7045+
bool EffectivelyConstexprDestructor = true;
7046+
// Avoid triggering vtable instantiation due to a dtor that is not
7047+
// "effectively constexpr" for better compatibility.
7048+
// See https://github.com/llvm/llvm-project/issues/102293 for more info.
7049+
if (isa<CXXDestructorDecl>(M)) {
7050+
auto Check = [](QualType T, auto &&Check) -> bool {
7051+
const CXXRecordDecl *RD =
7052+
T->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
7053+
if (!RD || !RD->isCompleteDefinition())
7054+
return true;
7055+
7056+
if (!RD->hasConstexprDestructor())
7057+
return false;
7058+
7059+
for (const CXXBaseSpecifier &B : RD->bases())
7060+
if (!Check(B.getType(), Check))
7061+
return false;
7062+
for (const FieldDecl *FD : RD->fields())
7063+
if (!Check(FD->getType(), Check))
7064+
return false;
7065+
return true;
7066+
};
7067+
EffectivelyConstexprDestructor =
7068+
Check(QualType(Record->getTypeForDecl(), 0), Check);
7069+
}
7070+
70457071
// Define defaulted constexpr virtual functions that override a base class
70467072
// function right away.
70477073
// FIXME: We can defer doing this until the vtable is marked as used.
70487074
if (CSM != CXXSpecialMemberKind::Invalid && !M->isDeleted() &&
7049-
M->isDefaulted() && M->isConstexpr() && M->size_overridden_methods())
7075+
M->isDefaulted() && M->isConstexpr() && M->size_overridden_methods() &&
7076+
EffectivelyConstexprDestructor)
70507077
DefineDefaultedFunction(*this, M, M->getLocation());
70517078

70527079
if (!Incomplete)

clang/test/SemaCXX/gh102293.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: %clang_cc1 -std=c++23 -fsyntax-only -verify %s
2+
// expected-no-diagnostics
3+
4+
template <typename T> static void destroy() {
5+
T t;
6+
++t;
7+
}
8+
9+
struct Incomplete;
10+
11+
template <typename = int> struct HasD {
12+
~HasD() { destroy<Incomplete*>(); }
13+
};
14+
15+
struct HasVT {
16+
virtual ~HasVT();
17+
};
18+
19+
struct S : HasVT {
20+
HasD<> v;
21+
};
22+

0 commit comments

Comments
 (0)