From 1bdee855b52369afe479fba61ce6af926d427c61 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Fri, 22 Sep 2017 01:04:22 +0000 Subject: [PATCH] Fix tracking of whether a destructor would be deleted. I've been unable to find any cases whose behavior is actually changed by this, but only because an implicitly deleted destructor also results in it being impossible to have a trivial (non-deleted) copy constructor, which the place where this really matters (choosing whether to pass a class in registers) happens to also check. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@313948 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/DeclCXX.h | 14 +++++++++++++- lib/Sema/SemaDecl.cpp | 4 +++- test/CXX/special/class.dtor/p5-implicit.cpp | 21 +++++++++++++++++++++ 3 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 test/CXX/special/class.dtor/p5-implicit.cpp diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index e2391d785d..d85ace9dda 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -838,7 +838,10 @@ public: /// \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, @@ -985,6 +988,15 @@ public: 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 { diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 063a0b262b..33f02c5b7f 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -15119,8 +15119,10 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, if (CXXRecordDecl *CXXRecord = dyn_cast(Record)) { auto *Dtor = CXXRecord->getDestructor(); if (Dtor && Dtor->isImplicit() && - ShouldDeleteSpecialMember(Dtor, CXXDestructor)) + ShouldDeleteSpecialMember(Dtor, CXXDestructor)) { + CXXRecord->setImplicitDestructorIsDeleted(); SetDeclDeleted(Dtor, CXXRecord->getLocation()); + } } if (Record->hasAttrs()) { diff --git a/test/CXX/special/class.dtor/p5-implicit.cpp b/test/CXX/special/class.dtor/p5-implicit.cpp new file mode 100644 index 0000000000..703be15b70 --- /dev/null +++ b/test/CXX/special/class.dtor/p5-implicit.cpp @@ -0,0 +1,21 @@ +// 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 -- 2.40.0