diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index c880e2812c38..49cf721579ec 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -722,6 +722,13 @@ void CXXRecordDecl::addedMember(Decl *D) { if (FieldRec->getDefinition()) { addedClassSubobject(FieldRec); + // We may need to perform overload resolution to determine whether a + // field can be moved if it's const or volatile qualified. + if (T.getCVRQualifiers() & (Qualifiers::Const | Qualifiers::Volatile)) { + data().NeedOverloadResolutionForMoveConstructor = true; + data().NeedOverloadResolutionForMoveAssignment = true; + } + // C++11 [class.ctor]p5, C++11 [class.copy]p11: // A defaulted [special member] for a class X is defined as // deleted if: diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 54eef40043b6..28c5af50f144 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -4913,6 +4913,10 @@ struct SpecialMemberDeletionInfo { // cv-qualifiers on class members don't affect default ctor / dtor calls. if (CSM == Sema::CXXDefaultConstructor || CSM == Sema::CXXDestructor) Quals = 0; + // cv-qualifiers on class members affect the type of both '*this' and the + // argument for an assignment. + if (IsAssignment) + TQ |= Quals; return S.LookupSpecialMember(Class, CSM, ConstArg || (Quals & Qualifiers::Const), VolatileArg || (Quals & Qualifiers::Volatile), diff --git a/clang/test/CXX/except/except.spec/p14.cpp b/clang/test/CXX/except/except.spec/p14.cpp index dda69e9aad60..945a767584fe 100644 --- a/clang/test/CXX/except/except.spec/p14.cpp +++ b/clang/test/CXX/except/except.spec/p14.cpp @@ -44,8 +44,8 @@ namespace PR13381 { struct NoThrowMove { NoThrowMove(const NoThrowMove &); NoThrowMove(NoThrowMove &&) noexcept; - NoThrowMove &operator=(const NoThrowMove &); - NoThrowMove &operator=(NoThrowMove &&) noexcept; + NoThrowMove &operator=(const NoThrowMove &) const; + NoThrowMove &operator=(NoThrowMove &&) const noexcept; }; struct NoThrowMoveOnly { NoThrowMoveOnly(NoThrowMoveOnly &&) noexcept; diff --git a/clang/test/CXX/special/class.copy/p11.0x.copy.cpp b/clang/test/CXX/special/class.copy/p11.0x.copy.cpp index 011c1e9a8760..a334c50e9fda 100644 --- a/clang/test/CXX/special/class.copy/p11.0x.copy.cpp +++ b/clang/test/CXX/special/class.copy/p11.0x.copy.cpp @@ -1,5 +1,6 @@ // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s +struct Trivial {}; struct NonTrivial { NonTrivial(const NonTrivial&); }; @@ -69,6 +70,12 @@ struct Deleted { Deleted Da; Deleted Db(Da); // expected-error{{call to implicitly-deleted copy constructor}} +// It's implied (but not stated) that this also applies in the case where +// overload resolution would fail. +struct VolatileMember { + volatile Trivial vm; // expected-note {{has no copy}} +} vm1, vm2(vm1); // expected-error {{deleted}} + // -- a direct or virtual base class B that cannot be copied because overload // resolution results in an ambiguity or a function that is deleted or // inaccessible diff --git a/clang/test/CXX/special/class.copy/p11.0x.move.cpp b/clang/test/CXX/special/class.copy/p11.0x.move.cpp index ebcce491c404..1dce27a83290 100644 --- a/clang/test/CXX/special/class.copy/p11.0x.move.cpp +++ b/clang/test/CXX/special/class.copy/p11.0x.move.cpp @@ -1,5 +1,6 @@ // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s +struct Trivial {}; struct NonTrivial { NonTrivial(NonTrivial&&); }; @@ -61,6 +62,24 @@ struct Deleted { }; Deleted::Deleted(Deleted&&) = default; // expected-error{{would delete}} +// It's implied (but not stated) that this should also happen if overload +// resolution fails. +struct ConstMember { + const Trivial ct; + ConstMember(ConstMember&&); +}; +ConstMember::ConstMember(ConstMember&&) = default; // ok, calls copy ctor +struct ConstMoveOnlyMember { + const NonTrivial cnt; + ConstMoveOnlyMember(ConstMoveOnlyMember&&); +}; +ConstMoveOnlyMember::ConstMoveOnlyMember(ConstMoveOnlyMember&&) = default; // expected-error{{would delete}} +struct VolatileMember { + volatile Trivial vt; + VolatileMember(VolatileMember&&); +}; +VolatileMember::VolatileMember(VolatileMember&&) = default; // expected-error{{would delete}} + // -- a direct or virtual base class B that cannot be moved because overload // resolution results in an ambiguity or a function that is deleted or // inaccessible diff --git a/clang/test/CXX/special/class.copy/p23-cxx11.cpp b/clang/test/CXX/special/class.copy/p23-cxx11.cpp index c55d6c268ad8..de071f050f01 100644 --- a/clang/test/CXX/special/class.copy/p23-cxx11.cpp +++ b/clang/test/CXX/special/class.copy/p23-cxx11.cpp @@ -1,5 +1,7 @@ // RUN: %clang_cc1 -verify %s -std=c++11 +struct Trivial {}; + template struct CopyAssign { static T t; void test() { @@ -47,6 +49,9 @@ class InaccessibleCopyAssign { class InaccessibleMoveAssign { InaccessibleMoveAssign &operator=(InaccessibleMoveAssign &&); }; +class NonConstCopyAssign { + NonConstCopyAssign &operator=(NonConstCopyAssign &); +}; // A defaulted copy/move assignment operator for class X is defined as deleted // if X has: @@ -114,6 +119,12 @@ struct D6 { D6 &operator=(D6 &&) = default; // expected-note {{here}} expected-note {{copy assignment operator is implicitly deleted}} InaccessibleMoveAssign a; // expected-note {{field 'a' has an inaccessible move}} }; +struct D7 { + const Trivial a; // expected-note 3{{field 'a' has no }} +}; +struct D8 { + volatile Trivial a; // expected-note 3{{field 'a' has no }} +}; template struct CopyAssign; // expected-note {{here}} template struct MoveAssign; // expected-note {{here}} template struct MoveOrCopyAssign; // expected-note {{here}} @@ -123,6 +134,12 @@ template struct MoveOrCopyAssign; // expected-note {{here}} template struct CopyAssign; // expected-note {{here}} template struct MoveAssign; // expected-note {{here}} template struct MoveOrCopyAssign; // expected-note {{here}} +template struct CopyAssign; // expected-note {{here}} +template struct MoveAssign; // expected-note {{here}} +template struct MoveOrCopyAssign; // expected-note {{here}} +template struct CopyAssign; // expected-note {{here}} +template struct MoveAssign; // expected-note {{here}} +template struct MoveOrCopyAssign; // expected-note {{here}} // -- a direct or virtual base that cannot be copied/moved struct E1 : AmbiguousCopyAssign {}; // expected-note {{base class 'AmbiguousCopyAssign' has multiple copy}} @@ -147,7 +164,7 @@ template struct MoveAssign; // expected-note {{here}} namespace PR13381 { struct S { S &operator=(const S&); - S &operator=(const volatile S&) = delete; // expected-note{{deleted here}} + S &operator=(const volatile S&) volatile = delete; // expected-note{{deleted here}} }; struct T { volatile S s; // expected-note{{field 's' has a deleted copy assignment}}