[clang] [clang] Avoid triggering vtable instantiation for C++23 constexpr dtor (PR #102605)
Mariya Podchishchaeva via cfe-commits
cfe-commits at lists.llvm.org
Fri Aug 9 07:18:22 PDT 2024
https://github.com/Fznamznon updated https://github.com/llvm/llvm-project/pull/102605
>From eb97afb9cade7b496ec55acdd4f02a915c4a4955 Mon Sep 17 00:00:00 2001
From: "Podchishchaeva, Mariya" <mariya.podchishchaeva at intel.com>
Date: Fri, 9 Aug 2024 05:20:37 -0700
Subject: [PATCH 1/2] [clang] Avoid triggering vtable instantiation for C++23
constexpr dtor
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 https://github.com/llvm/llvm-project/issues/102293
---
clang/lib/Sema/SemaDeclCXX.cpp | 28 +++++++++++++++++++++++++++-
clang/test/SemaCXX/gh102293.cpp | 22 ++++++++++++++++++++++
2 files changed, 49 insertions(+), 1 deletion(-)
create mode 100644 clang/test/SemaCXX/gh102293.cpp
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index b07e555afcaccf..63d2131acdd650 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -7042,12 +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.
+ 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())
- DefineDefaultedFunction(*this, M, M->getLocation());
+ if (EffectivelyConstexprDestructor)
+ DefineDefaultedFunction(*this, M, M->getLocation());
if (!Incomplete)
CheckCompletedMemberFunction(M);
diff --git a/clang/test/SemaCXX/gh102293.cpp b/clang/test/SemaCXX/gh102293.cpp
new file mode 100644
index 00000000000000..30629fc03bf6a9
--- /dev/null
+++ b/clang/test/SemaCXX/gh102293.cpp
@@ -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;
+};
+
>From 41857fe433eb141720b24e12a07e5a5fc57d87fa Mon Sep 17 00:00:00 2001
From: "Podchishchaeva, Mariya" <mariya.podchishchaeva at intel.com>
Date: Fri, 9 Aug 2024 07:17:51 -0700
Subject: [PATCH 2/2] Add issue link, merge ifs
---
clang/lib/Sema/SemaDeclCXX.cpp | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 63d2131acdd650..c87edf41f35cee 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -7045,6 +7045,7 @@ 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 =
@@ -7071,9 +7072,9 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) {
// 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())
- if (EffectivelyConstexprDestructor)
- DefineDefaultedFunction(*this, M, M->getLocation());
+ M->isDefaulted() && M->isConstexpr() && M->size_overridden_methods() &&
+ EffectivelyConstexprDestructor)
+ DefineDefaultedFunction(*this, M, M->getLocation());
if (!Incomplete)
CheckCompletedMemberFunction(M);
More information about the cfe-commits
mailing list