]> granicus.if.org Git - clang/commitdiff
Fix tracking of whether a destructor would be deleted.
authorRichard Smith <richard-llvm@metafoo.co.uk>
Fri, 22 Sep 2017 01:04:22 +0000 (01:04 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Fri, 22 Sep 2017 01:04:22 +0000 (01:04 +0000)
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
lib/Sema/SemaDecl.cpp
test/CXX/special/class.dtor/p5-implicit.cpp [new file with mode: 0644]

index e2391d785d9b55c6879d5702f71467bfd74b157c..d85ace9dda06bc50387f155e0b01749178a867bd 100644 (file)
@@ -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 {
index 063a0b262b2dce1a80db85e6aadacb8f2b684044..33f02c5b7f4bf27c2e47be44e4e905205afbfca8 100644 (file)
@@ -15119,8 +15119,10 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
     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()) {
diff --git a/test/CXX/special/class.dtor/p5-implicit.cpp b/test/CXX/special/class.dtor/p5-implicit.cpp
new file mode 100644 (file)
index 0000000..703be15
--- /dev/null
@@ -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