From 517bb844016064f303416f09f1aeb123e32c0f66 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Wed, 18 Jul 2012 03:51:16 +0000 Subject: [PATCH] PR13381, part 2: when determining if a defaulted special member function should be defined as deleted, take cv-qualifiers on class members into account when looking up the copy or move constructor or assignment operator which will be used for them. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@160418 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaDeclCXX.cpp | 27 ++++++++++++++------- test/CXX/special/class.copy/p11.0x.copy.cpp | 12 +++++++++ test/CXX/special/class.copy/p23-cxx11.cpp | 14 +++++++++++ 3 files changed, 44 insertions(+), 9 deletions(-) diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index a4528eda0f..2a5c0dae43 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -4235,9 +4235,15 @@ struct SpecialMemberDeletionInfo { bool inUnion() const { return MD->getParent()->isUnion(); } /// Look up the corresponding special member in the given class. - Sema::SpecialMemberOverloadResult *lookupIn(CXXRecordDecl *Class) { + Sema::SpecialMemberOverloadResult *lookupIn(CXXRecordDecl *Class, + unsigned Quals) { unsigned TQ = MD->getTypeQualifiers(); - return S.LookupSpecialMember(Class, CSM, ConstArg, VolatileArg, + // cv-qualifiers on class members don't affect default ctor / dtor calls. + if (CSM == Sema::CXXDefaultConstructor || CSM == Sema::CXXDestructor) + Quals = 0; + return S.LookupSpecialMember(Class, CSM, + ConstArg || (Quals & Qualifiers::Const), + VolatileArg || (Quals & Qualifiers::Volatile), MD->getRefQualifier() == RQ_RValue, TQ & Qualifiers::Const, TQ & Qualifiers::Volatile); @@ -4249,7 +4255,8 @@ struct SpecialMemberDeletionInfo { bool shouldDeleteForField(FieldDecl *FD); bool shouldDeleteForAllConstMembers(); - bool shouldDeleteForClassSubobject(CXXRecordDecl *Class, Subobject Subobj); + bool shouldDeleteForClassSubobject(CXXRecordDecl *Class, Subobject Subobj, + unsigned Quals); bool shouldDeleteForSubobjectCall(Subobject Subobj, Sema::SpecialMemberOverloadResult *SMOR, bool IsDtorCallInCtor); @@ -4330,9 +4337,9 @@ bool SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall( } /// Check whether we should delete a special member function due to having a -/// direct or virtual base class or static data member of class type M. +/// direct or virtual base class or non-static data member of class type M. bool SpecialMemberDeletionInfo::shouldDeleteForClassSubobject( - CXXRecordDecl *Class, Subobject Subobj) { + CXXRecordDecl *Class, Subobject Subobj, unsigned Quals) { FieldDecl *Field = Subobj.dyn_cast(); // C++11 [class.ctor]p5: @@ -4351,7 +4358,7 @@ bool SpecialMemberDeletionInfo::shouldDeleteForClassSubobject( // that is deleted or inaccessible if (!(CSM == Sema::CXXDefaultConstructor && Field && Field->hasInClassInitializer()) && - shouldDeleteForSubobjectCall(Subobj, lookupIn(Class), false)) + shouldDeleteForSubobjectCall(Subobj, lookupIn(Class, Quals), false)) return true; // C++11 [class.ctor]p5, C++11 [class.copy]p11: @@ -4372,7 +4379,7 @@ bool SpecialMemberDeletionInfo::shouldDeleteForClassSubobject( /// having a particular direct or virtual base class. bool SpecialMemberDeletionInfo::shouldDeleteForBase(CXXBaseSpecifier *Base) { CXXRecordDecl *BaseClass = Base->getType()->getAsCXXRecordDecl(); - return shouldDeleteForClassSubobject(BaseClass, Base); + return shouldDeleteForClassSubobject(BaseClass, Base, 0); } /// Check whether we should delete a special member function due to the class @@ -4449,7 +4456,8 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) { CXXRecordDecl *UnionFieldRecord = UnionFieldType->getAsCXXRecordDecl(); if (UnionFieldRecord && - shouldDeleteForClassSubobject(UnionFieldRecord, *UI)) + shouldDeleteForClassSubobject(UnionFieldRecord, *UI, + UnionFieldType.getCVRQualifiers())) return true; } @@ -4468,7 +4476,8 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) { return false; } - if (shouldDeleteForClassSubobject(FieldRecord, FD)) + if (shouldDeleteForClassSubobject(FieldRecord, FD, + FieldType.getCVRQualifiers())) return true; } diff --git a/test/CXX/special/class.copy/p11.0x.copy.cpp b/test/CXX/special/class.copy/p11.0x.copy.cpp index 2274700c5b..fab3b9dd7b 100644 --- a/test/CXX/special/class.copy/p11.0x.copy.cpp +++ b/test/CXX/special/class.copy/p11.0x.copy.cpp @@ -119,3 +119,15 @@ struct RValue { }; RValue RVa; RValue RVb(RVa); // expected-error{{call to implicitly-deleted copy constructor}} + +namespace PR13381 { + struct S { + S(const S&); + S(const volatile S&) = delete; // expected-note{{deleted here}} + }; + struct T { + volatile S s; // expected-note{{field 's' has a deleted copy constructor}} + }; + T &f(); + T t = f(); // expected-error{{call to implicitly-deleted copy constructor}} +} diff --git a/test/CXX/special/class.copy/p23-cxx11.cpp b/test/CXX/special/class.copy/p23-cxx11.cpp index 62a0843bfa..7c04a82018 100644 --- a/test/CXX/special/class.copy/p23-cxx11.cpp +++ b/test/CXX/special/class.copy/p23-cxx11.cpp @@ -132,3 +132,17 @@ template struct CopyAssign; // expected-note {{here}} template struct MoveAssign; // expected-note {{here}} template struct CopyAssign; // expected-note {{here}} template struct MoveAssign; // expected-note {{here}} + +namespace PR13381 { + struct S { + S &operator=(const S&); + S &operator=(const volatile S&) = delete; // expected-note{{deleted here}} + }; + struct T { + volatile S s; // expected-note{{field 's' has a deleted copy assignment}} + }; + void g() { + T t; + t = T(); // expected-error{{implicitly-deleted copy assignment}} + } +} -- 2.50.1