<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>