<html><head></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; ">Hi Richard,<div>We have a number of regression test failures on our MSVC buildbot and I suspect this commit or another related commit is causing the problem.  Unfortunately, I don't have an easy way of reproducing the failures as I don't have a Windows machine.  Would you mind taking a look?  </div><div><br></div><div>The specific tests are:</div><div><span style="font-family: 'Courier New', courier, monotype; ">********************</span></div><div><pre style="font-family: 'Courier New', courier, monotype; "><span class="stdout">Failing Tests (13):
    Clang :: CXX/dcl.dcl/dcl.spec/dcl.typedef/p2-0x.cpp
    Clang :: CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp
    Clang :: CXX/dcl.decl/p4-0x.cpp
    Clang :: CXX/expr/expr.mptr.oper/p6-0x.cpp
    Clang :: CXX/over/over.load/p2-0x.cpp
    Clang :: CXX/over/over.match/over.match.funcs/p4-0x.cpp
    Clang :: CXX/special/class.ctor/p4-0x.cpp
    Clang :: CXX/special/class.dtor/p2-0x.cpp
    Clang :: CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p8-0x.cpp
    Clang :: CodeGenCXX/mangle-ref-qualifiers.cpp
    Clang :: SemaCXX/alias-template.cpp
    Clang :: SemaCXX/cxx0x-cursory-default-delete.cpp
    Clang :: SemaCXX/issue547.cpp</span></pre><div>These tests began failing between r151468 and r151514.</div><div><br></div><div> Chad</div></div><div><br></div><div><br><div><div>On Feb 26, 2012, at 1:11 AM, Richard Smith <<a href="mailto:richard-llvm@metafoo.co.uk">richard-llvm@metafoo.co.uk</a>> wrote:</div><br class="Apple-interchange-newline"><blockquote type="cite"><div>Author: rsmith<br>Date: Sun Feb 26 03:11:52 2012<br>New Revision: 151483<br><br>URL: <a href="http://llvm.org/viewvc/llvm-project?rev=151483&view=rev">http://llvm.org/viewvc/llvm-project?rev=151483&view=rev</a><br>Log:<br>Ensure that we delete destructors in the right cases. Specifically:<br> - variant members with nontrivial destructors make the containing class's<br>   destructor deleted<br> - check for a virtual destructor after checking for overridden methods in the<br>   base class(es)<br> - check for an inaccessible operator delete for a class with a virtual<br>   destructor.<br><br>Do not try to call an anonymous union field's destructor from the destructor of<br>the containing class.<br><br>Added:<br>    cfe/trunk/test/CXX/special/class.dtor/p5-0x.cpp<br>Modified:<br>    cfe/trunk/lib/CodeGen/CGClass.cpp<br>    cfe/trunk/lib/Sema/SemaDeclCXX.cpp<br>    cfe/trunk/lib/Sema/SemaExprCXX.cpp<br><br>Modified: cfe/trunk/lib/CodeGen/CGClass.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGClass.cpp?rev=151483&r1=151482&r2=151483&view=diff">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGClass.cpp?rev=151483&r1=151482&r2=151483&view=diff</a><br>==============================================================================<br>--- cfe/trunk/lib/CodeGen/CGClass.cpp (original)<br>+++ cfe/trunk/lib/CodeGen/CGClass.cpp Sun Feb 26 03:11:52 2012<br>@@ -1062,6 +1062,10 @@<br>     QualType::DestructionKind dtorKind = type.isDestructedType();<br>     if (!dtorKind) continue;<br><br>+    // Anonymous union members do not have their destructors called.<br>+    const RecordType *RT = type->getAsUnionType();<br>+    if (RT && RT->getDecl()->isAnonymousStructOrUnion()) continue;<br>+<br>     CleanupKind cleanupKind = getCleanupKind(dtorKind);<br>     EHStack.pushCleanup<DestroyField>(cleanupKind, field,<br>                                       getDestroyer(dtorKind),<br><br>Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=151483&r1=151482&r2=151483&view=diff">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=151483&r1=151482&r2=151483&view=diff</a><br>==============================================================================<br>--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)<br>+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Sun Feb 26 03:11:52 2012<br>@@ -3293,6 +3293,9 @@<br>       continue;<br>     if (FieldClassDecl->hasIrrelevantDestructor())<br>       continue;<br>+    // The destructor for an implicit anonymous union member is never invoked.<br>+    if (FieldClassDecl->isUnion() && FieldClassDecl->isAnonymousStructOrUnion())<br>+      continue;<br><br>     CXXDestructorDecl *Dtor = LookupDestructor(FieldClassDecl);<br>     assert(Dtor && "No dtor found for FieldClassDecl!");<br>@@ -4372,31 +4375,33 @@<br>                                  TQ & Qualifiers::Volatile);<br>   }<br><br>+  bool shouldDeleteForClassSubobject(CXXRecordDecl *Class, FieldDecl *Field);<br>+<br>   bool shouldDeleteForBase(CXXRecordDecl *BaseDecl, bool IsVirtualBase);<br>   bool shouldDeleteForField(FieldDecl *FD);<br>   bool shouldDeleteForAllConstMembers();<br> };<br> }<br><br>-/// Check whether we should delete a special member function due to the class<br>-/// having a particular direct or virtual base class.<br>-bool SpecialMemberDeletionInfo::shouldDeleteForBase(CXXRecordDecl *BaseDecl,<br>-                                                    bool IsVirtualBase) {<br>-  // C++11 [class.copy]p23:<br>-  // -- for the move assignment operator, any direct or indirect virtual<br>-  //    base class.<br>-  if (CSM == Sema::CXXMoveAssignment && IsVirtualBase)<br>-    return true;<br>-<br>+/// Check whether we should delete a special member function due to having a<br>+/// direct or virtual base class or static data member of class type M.<br>+bool SpecialMemberDeletionInfo::shouldDeleteForClassSubobject(<br>+    CXXRecordDecl *Class, FieldDecl *Field) {<br>   // C++11 [class.ctor]p5, C++11 [class.copy]p11, C++11 [class.dtor]p5:<br>   // -- any direct or virtual base class [...] has a type with a destructor<br>   //    that is deleted or inaccessible<br>   if (!IsAssignment) {<br>-    CXXDestructorDecl *BaseDtor = S.LookupDestructor(BaseDecl);<br>-    if (BaseDtor->isDeleted())<br>+    CXXDestructorDecl *Dtor = S.LookupDestructor(Class);<br>+    if (Dtor->isDeleted())<br>       return true;<br>-    if (S.CheckDestructorAccess(Loc, BaseDtor, S.PDiag())<br>-          != Sema::AR_accessible)<br>+    if (S.CheckDestructorAccess(Loc, Dtor, S.PDiag()) != Sema::AR_accessible)<br>+      return true;<br>+<br>+    // C++11 [class.dtor]p5:<br>+    // -- X is a union-like class that has a variant member with a non-trivial<br>+    //    destructor<br>+    if (CSM == Sema::CXXDestructor && Field && Field->getParent()->isUnion() &&<br>+        !Dtor->isTrivial())<br>       return true;<br>   }<br><br>@@ -4410,50 +4415,58 @@<br>   //    overload resolution, as applied to B's corresponding special member,<br>   //    results in an ambiguity or a function that is deleted or inaccessible<br>   //    from the defaulted special member<br>+  // FIXME: in-class initializers should be handled here<br>   if (CSM != Sema::CXXDestructor) {<br>-    Sema::SpecialMemberOverloadResult *SMOR = lookupIn(BaseDecl);<br>+    Sema::SpecialMemberOverloadResult *SMOR = lookupIn(Class);<br>     if (!SMOR->hasSuccess())<br>       return true;<br><br>-    CXXMethodDecl *BaseMember = SMOR->getMethod();<br>+    CXXMethodDecl *Member = SMOR->getMethod();<br>+    // A member of a union must have a trivial corresponding special member.<br>+    if (Field && Field->getParent()->isUnion() && !Member->isTrivial())<br>+      return true;<br>+<br>     if (IsConstructor) {<br>-      CXXConstructorDecl *BaseCtor = cast<CXXConstructorDecl>(BaseMember);<br>-      if (S.CheckConstructorAccess(Loc, BaseCtor, BaseCtor->getAccess(),<br>-                                   S.PDiag()) != Sema::AR_accessible)<br>+      CXXConstructorDecl *Ctor = cast<CXXConstructorDecl>(Member);<br>+      if (S.CheckConstructorAccess(Loc, Ctor, Ctor->getAccess(), S.PDiag())<br>+            != Sema::AR_accessible)<br>         return true;<br><br>       // -- for the move constructor, a [...] direct or virtual base class with<br>       //    a type that does not have a move constructor and is not trivially<br>       //    copyable.<br>-      if (IsMove && !BaseCtor->isMoveConstructor() &&<br>-          !BaseDecl->isTriviallyCopyable())<br>+      if (IsMove && !Ctor->isMoveConstructor() && !Class->isTriviallyCopyable())<br>         return true;<br>     } else {<br>       assert(IsAssignment && "unexpected kind of special member");<br>-      if (S.CheckDirectMemberAccess(Loc, BaseMember, S.PDiag())<br>+      if (S.CheckDirectMemberAccess(Loc, Member, S.PDiag())<br>             != Sema::AR_accessible)<br>         return true;<br><br>       // -- for the move assignment operator, a direct base class with a type<br>       //    that does not have a move assignment operator and is not trivially<br>       //    copyable.<br>-      if (IsMove && !BaseMember->isMoveAssignmentOperator() &&<br>-          !BaseDecl->isTriviallyCopyable())<br>+      if (IsMove && !Member->isMoveAssignmentOperator() &&<br>+          !Class->isTriviallyCopyable())<br>         return true;<br>     }<br>   }<br><br>-  // C++11 [class.dtor]p5:<br>-  // -- for a virtual destructor, lookup of the non-array deallocation function<br>-  //    results in an ambiguity or in a function that is deleted or inaccessible<br>-  if (CSM == Sema::CXXDestructor && MD->isVirtual()) {<br>-    FunctionDecl *OperatorDelete = 0;<br>-    DeclarationName Name =<br>-      S.Context.DeclarationNames.getCXXOperatorName(OO_Delete);<br>-    if (S.FindDeallocationFunction(Loc, MD->getParent(), Name,<br>-                                   OperatorDelete, false))<br>-      return true;<br>-  }<br>+  return false;<br>+}<br>+<br>+/// Check whether we should delete a special member function due to the class<br>+/// having a particular direct or virtual base class.<br>+bool SpecialMemberDeletionInfo::shouldDeleteForBase(CXXRecordDecl *BaseDecl,<br>+                                                    bool IsVirtualBase) {<br>+  // C++11 [class.copy]p23:<br>+  // -- for the move assignment operator, any direct or indirect virtual<br>+  //    base class.<br>+  if (CSM == Sema::CXXMoveAssignment && IsVirtualBase)<br>+    return true;<br>+<br>+  if (shouldDeleteForClassSubobject(BaseDecl, 0))<br>+    return true;<br><br>   return false;<br> }<br>@@ -4500,58 +4513,14 @@<br>                                          UE = FieldRecord->field_end();<br>            UI != UE; ++UI) {<br>         QualType UnionFieldType = S.Context.getBaseElementType(UI->getType());<br>-        CXXRecordDecl *UnionFieldRecord =<br>-          UnionFieldType->getAsCXXRecordDecl();<br><br>         if (!UnionFieldType.isConstQualified())<br>           AllVariantFieldsAreConst = false;<br><br>-        if (UnionFieldRecord) {<br>-          // FIXME: Checking for accessibility and validity of this<br>-          //        destructor is technically going beyond the<br>-          //        standard, but this is believed to be a defect.<br>-          if (!IsAssignment) {<br>-            CXXDestructorDecl *FieldDtor = S.LookupDestructor(UnionFieldRecord);<br>-            if (FieldDtor->isDeleted())<br>-              return true;<br>-            if (S.CheckDestructorAccess(Loc, FieldDtor, S.PDiag()) !=<br>-                Sema::AR_accessible)<br>-              return true;<br>-            if (!FieldDtor->isTrivial())<br>-              return true;<br>-          }<br>-<br>-          // FIXME: in-class initializers should be handled here<br>-          if (CSM != Sema::CXXDestructor) {<br>-            Sema::SpecialMemberOverloadResult *SMOR =<br>-                lookupIn(UnionFieldRecord);<br>-            // FIXME: Checking for accessibility and validity of this<br>-            //        corresponding member is technically going beyond the<br>-            //        standard, but this is believed to be a defect.<br>-            if (!SMOR->hasSuccess())<br>-              return true;<br>-<br>-            CXXMethodDecl *FieldMember = SMOR->getMethod();<br>-            // A member of a union must have a trivial corresponding<br>-            // special member.<br>-            if (!FieldMember->isTrivial())<br>-              return true;<br>-<br>-            if (IsConstructor) {<br>-              CXXConstructorDecl *FieldCtor =<br>-                  cast<CXXConstructorDecl>(FieldMember);<br>-              if (S.CheckConstructorAccess(Loc, FieldCtor,<br>-                                           FieldCtor->getAccess(),<br>-                                           S.PDiag()) != Sema::AR_accessible)<br>-              return true;<br>-            } else {<br>-              assert(IsAssignment && "unexpected kind of special member");<br>-              if (S.CheckDirectMemberAccess(Loc, FieldMember, S.PDiag())<br>-                  != Sema::AR_accessible)<br>-                return true;<br>-            }<br>-          }<br>-        }<br>+        CXXRecordDecl *UnionFieldRecord = UnionFieldType->getAsCXXRecordDecl();<br>+        if (UnionFieldRecord &&<br>+            shouldDeleteForClassSubobject(UnionFieldRecord, *UI))<br>+          return true;<br>       }<br><br>       // At least one member in each anonymous union must be non-const<br>@@ -4564,9 +4533,9 @@<br>       return false;<br>     }<br><br>-    // Unless we're doing assignment, the field's destructor must be<br>-    // accessible and not deleted.<br>-    if (!IsAssignment) {<br>+    // When checking a constructor, the field's destructor must be accessible<br>+    // and not deleted.<br>+    if (IsConstructor) {<br>       CXXDestructorDecl *FieldDtor = S.LookupDestructor(FieldRecord);<br>       if (FieldDtor->isDeleted())<br>         return true;<br>@@ -4578,13 +4547,18 @@<br>     // Check that the corresponding member of the field is accessible,<br>     // unique, and non-deleted. We don't do this if it has an explicit<br>     // initialization when default-constructing.<br>-    if (CSM != Sema::CXXDestructor &&<br>-        !(CSM == Sema::CXXDefaultConstructor && FD->hasInClassInitializer())) {<br>+    if (!(CSM == Sema::CXXDefaultConstructor && FD->hasInClassInitializer())) {<br>       Sema::SpecialMemberOverloadResult *SMOR = lookupIn(FieldRecord);<br>       if (!SMOR->hasSuccess())<br>         return true;<br><br>       CXXMethodDecl *FieldMember = SMOR->getMethod();<br>+<br>+      // We need the corresponding member of a union to be trivial so that<br>+      // we can safely process all members simultaneously.<br>+      if (inUnion() && !FieldMember->isTrivial())<br>+        return true;<br>+<br>       if (IsConstructor) {<br>         CXXConstructorDecl *FieldCtor = cast<CXXConstructorDecl>(FieldMember);<br>         if (S.CheckConstructorAccess(Loc, FieldCtor, FieldCtor->getAccess(),<br>@@ -4597,6 +4571,13 @@<br>         if (IsMove && !FieldCtor->isMoveConstructor() &&<br>             !FieldRecord->isTriviallyCopyable())<br>           return true;<br>+      } else if (CSM == Sema::CXXDestructor) {<br>+        CXXDestructorDecl *FieldDtor = S.LookupDestructor(FieldRecord);<br>+        if (FieldDtor->isDeleted())<br>+          return true;<br>+        if (S.CheckDestructorAccess(Loc, FieldDtor, S.PDiag()) !=<br>+            Sema::AR_accessible)<br>+          return true;<br>       } else {<br>         assert(IsAssignment && "unexpected kind of special member");<br>         if (S.CheckDirectMemberAccess(Loc, FieldMember, S.PDiag())<br>@@ -4610,14 +4591,6 @@<br>             !FieldRecord->isTriviallyCopyable())<br>           return true;<br>       }<br>-<br>-      // We need the corresponding member of a union to be trivial so that<br>-      // we can safely copy them all simultaneously.<br>-      // FIXME: Note that performing the check here (where we rely on the lack<br>-      // of an in-class initializer) is technically ill-formed. However, this<br>-      // seems most obviously to be a bug in the standard.<br>-      if (inUnion() && !FieldMember->isTrivial())<br>-        return true;<br>     }<br>   } else if (CSM == Sema::CXXDefaultConstructor && !inUnion() &&<br>              FieldType.isConstQualified() && !FD->hasInClassInitializer()) {<br>@@ -4652,6 +4625,8 @@<br>   if (!LangOpts.CPlusPlus0x || RD->isInvalidDecl())<br>     return false;<br><br>+  // FIXME: Provide the ability to diagnose why a special member was deleted.<br>+<br>   // C++11 [expr.lambda.prim]p19:<br>   //   The closure type associated with a lambda-expression has a<br>   //   deleted (8.4.3) default constructor and a deleted copy<br>@@ -4660,6 +4635,18 @@<br>       (CSM == CXXDefaultConstructor || CSM == CXXCopyAssignment))<br>     return true;<br><br>+  // C++11 [class.dtor]p5:<br>+  // -- for a virtual destructor, lookup of the non-array deallocation function<br>+  //    results in an ambiguity or in a function that is deleted or inaccessible<br>+  if (CSM == Sema::CXXDestructor && MD->isVirtual()) {<br>+    FunctionDecl *OperatorDelete = 0;<br>+    DeclarationName Name =<br>+      Context.DeclarationNames.getCXXOperatorName(OO_Delete);<br>+    if (FindDeallocationFunction(MD->getLocation(), MD->getParent(), Name,<br>+                                 OperatorDelete, false))<br>+      return true;<br>+  }<br>+<br>   // For an anonymous struct or union, the copy and assignment special members<br>   // will never be used, so skip the check. For an anonymous union declared at<br>   // namespace scope, the constructor and destructor are used.<br>@@ -4672,8 +4659,6 @@<br><br>   SpecialMemberDeletionInfo SMI(*this, MD, CSM);<br><br>-  // FIXME: We should put some diagnostic logic right into this function.<br>-<br>   for (CXXRecordDecl::base_class_iterator BI = RD->bases_begin(),<br>                                           BE = RD->bases_end(); BI != BE; ++BI)<br>     if (!BI->isVirtual() &&<br>@@ -7216,11 +7201,11 @@<br>   // This could be uniqued if it ever proves significant.<br>   Destructor->setTypeSourceInfo(Context.getTrivialTypeSourceInfo(Ty));<br><br>+  AddOverriddenMethods(ClassDecl, Destructor);<br>+<br>   if (ShouldDeleteSpecialMember(Destructor, CXXDestructor))<br>     Destructor->setDeletedAsWritten();<br>-  <br>-  AddOverriddenMethods(ClassDecl, Destructor);<br>-  <br>+<br>   return Destructor;<br> }<br><br><br>Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=151483&r1=151482&r2=151483&view=diff">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=151483&r1=151482&r2=151483&view=diff</a><br>==============================================================================<br>--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)<br>+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Sun Feb 26 03:11:52 2012<br>@@ -1666,9 +1666,13 @@<br><br>       Args[i] = Result.takeAs<Expr>();<br>     }<br>+<br>     Operator = FnDecl;<br>-    CheckAllocationAccess(StartLoc, Range, R.getNamingClass(), Best->FoundDecl,<br>-                          Diagnose);<br>+<br>+    if (CheckAllocationAccess(StartLoc, Range, R.getNamingClass(),<br>+                              Best->FoundDecl, Diagnose) == AR_inaccessible)<br>+      return true;<br>+<br>     return false;<br>   }<br><br>@@ -1895,8 +1899,10 @@<br>       return true;<br>     }<br><br>-    CheckAllocationAccess(StartLoc, SourceRange(), Found.getNamingClass(),<br>-                          Matches[0], Diagnose);<br>+    if (CheckAllocationAccess(StartLoc, SourceRange(), Found.getNamingClass(),<br>+                              Matches[0], Diagnose) == AR_inaccessible)<br>+      return true;<br>+<br>     return false;<br><br>   // We found multiple suitable operators;  complain about the ambiguity.<br><br>Added: cfe/trunk/test/CXX/special/class.dtor/p5-0x.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/special/class.dtor/p5-0x.cpp?rev=151483&view=auto">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/special/class.dtor/p5-0x.cpp?rev=151483&view=auto</a><br>==============================================================================<br>--- cfe/trunk/test/CXX/special/class.dtor/p5-0x.cpp (added)<br>+++ cfe/trunk/test/CXX/special/class.dtor/p5-0x.cpp Sun Feb 26 03:11:52 2012<br>@@ -0,0 +1,103 @@<br>+// RUN: %clang_cc1 -verify -std=c++11 %s<br>+<br>+struct NonTrivDtor {<br>+  ~NonTrivDtor();<br>+};<br>+struct DeletedDtor {<br>+  ~DeletedDtor() = delete;<br>+};<br>+class InaccessibleDtor {<br>+  ~InaccessibleDtor() = default;<br>+};<br>+<br>+// A defaulted destructor for a class X is defined as deleted if:<br>+<br>+// -- X is a union-like class that has a variant member with a non-trivial<br>+// destructor.<br>+union A1 { // expected-note {{here}}<br>+  A1();<br>+  NonTrivDtor n;<br>+};<br>+A1 a1; // expected-error {{deleted function}}<br>+struct A2 { // expected-note {{here}}<br>+  A2();<br>+  union {<br>+    NonTrivDtor n;<br>+  };<br>+};<br>+A2 a2; // expected-error {{deleted function}}<br>+union A3 { // expected-note {{here}}<br>+  A3();<br>+  NonTrivDtor n[3];<br>+};<br>+A3 a3; // expected-error {{deleted function}}<br>+struct A4 { // expected-note {{here}}<br>+  A4();<br>+  union {<br>+    NonTrivDtor n[3];<br>+  };<br>+};<br>+A4 a4; // expected-error {{deleted function}}<br>+<br>+// -- any of the non-static data members has class type M (or array thereof) and<br>+// M has a deleted or inaccessible destructor.<br>+struct B1 { // expected-note {{here}}<br>+  B1();<br>+  DeletedDtor a;<br>+};<br>+B1 b1; // expected-error {{deleted function}}<br>+struct B2 { // expected-note {{here}}<br>+  B2();<br>+  InaccessibleDtor a;<br>+};<br>+B2 b2; // expected-error {{deleted function}}<br>+struct B3 { // expected-note {{here}}<br>+  B3();<br>+  DeletedDtor a[4];<br>+};<br>+B3 b3; // expected-error {{deleted function}}<br>+struct B4 { // expected-note {{here}}<br>+  B4();<br>+  InaccessibleDtor a[4];<br>+};<br>+B4 b4; // expected-error {{deleted function}}<br>+union B5 { // expected-note {{here}}<br>+  B5();<br>+  union {<br>+    DeletedDtor a;<br>+  };<br>+};<br>+B5 b5; // expected-error {{deleted function}}<br>+union B6 { // expected-note {{here}}<br>+  B6();<br>+  union {<br>+    InaccessibleDtor a;<br>+  };<br>+};<br>+B6 b6; // expected-error {{deleted function}}<br>+<br>+// -- any direct or virtual base class has a deleted or inaccessible destructor.<br>+struct C1 : DeletedDtor { C1(); } c1; // expected-error {{deleted function}} expected-note {{here}}<br>+struct C2 : InaccessibleDtor { C2(); } c2; // expected-error {{deleted function}} expected-note {{here}}<br>+struct C3 : virtual DeletedDtor { C3(); } c3; // expected-error {{deleted function}} expected-note {{here}}<br>+struct C4 : virtual InaccessibleDtor { C4(); } c4; // expected-error {{deleted function}} expected-note {{here}}<br>+<br>+// -- for a virtual destructor, lookup of the non-array deallocation function<br>+// results in an ambiguity or a function that is deleted or inaccessible.<br>+class D1 {<br>+  void operator delete(void*);<br>+public:<br>+  virtual ~D1() = default;<br>+} d1; // ok<br>+struct D2 : D1 { // expected-note {{deleted here}}<br>+  // implicitly-virtual destructor<br>+} d2; // expected-error {{deleted function}}<br>+struct D3 {<br>+  virtual ~D3() = default; // expected-note {{deleted here}}<br>+  void operator delete(void*, double = 0.0);<br>+  void operator delete(void*, char = 0);<br>+} d3; // expected-error {{deleted function}}<br>+struct D4 {<br>+  virtual ~D4() = default; // expected-note {{deleted here}}<br>+  void operator delete(void*) = delete;<br>+} d4; // expected-error {{deleted function}}<br><br><br>_______________________________________________<br>cfe-commits mailing list<br><a href="mailto:cfe-commits@cs.uiuc.edu">cfe-commits@cs.uiuc.edu</a><br>http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits<br></div></blockquote></div><br></div></body></html>