/// \brief \c true if a defaulted destructor for this class would be deleted.
bool defaultedDestructorIsDeleted() const {
- return !data().DefaultedDestructorIsDeleted;
+ assert((!needsOverloadResolutionForDestructor() ||
+ (data().DeclaredSpecialMembers & SMF_Destructor)) &&
+ "this property has not yet been computed by Sema");
+ return data().DefaultedDestructorIsDeleted;
}
/// \brief \c true if we know for sure that this class has a single,
data().DefaultedMoveConstructorIsDeleted = true;
}
+ /// \brief Set that we attempted to declare an implicit destructor,
+ /// but overload resolution failed so we deleted it.
+ void setImplicitDestructorIsDeleted() {
+ assert((data().DefaultedDestructorIsDeleted ||
+ needsOverloadResolutionForDestructor()) &&
+ "destructor should not be deleted");
+ data().DefaultedDestructorIsDeleted = true;
+ }
+
/// \brief Determine whether this class should get an implicit move
/// constructor or if any existing special member function inhibits this.
bool needsImplicitMoveConstructor() const {
if (CXXRecordDecl *CXXRecord = dyn_cast<CXXRecordDecl>(Record)) {
auto *Dtor = CXXRecord->getDestructor();
if (Dtor && Dtor->isImplicit() &&
- ShouldDeleteSpecialMember(Dtor, CXXDestructor))
+ ShouldDeleteSpecialMember(Dtor, CXXDestructor)) {
+ CXXRecord->setImplicitDestructorIsDeleted();
SetDeclDeleted(Dtor, CXXRecord->getLocation());
+ }
}
if (Record->hasAttrs()) {
--- /dev/null
+// RUN: %clang_cc1 -std=c++11 %s -ast-dump | FileCheck %s
+
+struct A { ~A() = delete; };
+// CHECK-LABEL: CXXRecordDecl {{.*}} struct A
+// CHECK: Destructor trivial user_declared
+
+struct B : A {};
+// CHECK-LABEL: CXXRecordDecl {{.*}} struct B
+// CHECK: Destructor trivial needs_overload_resolution
+
+struct C : B {};
+// CHECK-LABEL: CXXRecordDecl {{.*}} struct C
+// CHECK: Destructor trivial needs_overload_resolution
+
+struct D { ~D(); };
+struct E : D {};
+union U {
+ E e;
+};
+// CHECK-LABEL: CXXRecordDecl {{.*}} union U
+// CHECK: Destructor non_trivial needs_implicit defaulted_is_deleted