Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -1339,6 +1339,8 @@ def note_nontrivial_objc_ownership : Note< "because type %0 has a member with %select{no|no|__strong|__weak|" "__autoreleasing}1 ownership">; +def note_nontrivial_has_volatile_member : Note< + "because field %0 has volatile qualified type">; def err_static_data_member_not_allowed_in_anon_struct : Error< "static data member %0 not allowed in anonymous struct">; Index: lib/AST/DeclCXX.cpp =================================================================== --- lib/AST/DeclCXX.cpp +++ lib/AST/DeclCXX.cpp @@ -708,6 +708,16 @@ data().IsStandardLayout = false; } + // C++11 [class.copy]p12, C++11 [class.copy]p25: + // A [copy/move constructor, or copy/move assignment operator for a + // class X] is trivial [...] if: + // -- class X has no non-static data members of volatile-qualified + // type, [...] + if (T.isVolatileQualified()) + data().HasTrivialSpecialMembers &= + ~(SMF_CopyConstructor | SMF_MoveConstructor | SMF_CopyAssignment | + SMF_MoveAssignment); + // Record if this field is the first non-literal or volatile field or base. if (!T->isLiteralType(Context) || T.isVolatileQualified()) data().HasNonLiteralTypeFieldsOrBases = true; Index: lib/Sema/SemaDeclCXX.cpp =================================================================== --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -6065,6 +6065,20 @@ return false; } + // C++11 [class.copy]p12, C++11 [class.copy]p25: + // A copy/move [constructor or assignment operator] for a class X is + // trivial if + // -- class X has no non-static data members of volatile-qualified + // type, [...] + if ((CSM == Sema::CXXCopyConstructor || CSM == Sema::CXXCopyAssignment || + CSM == Sema::CXXMoveConstructor || CSM == Sema::CXXMoveAssignment) && + FieldType.isVolatileQualified()) { + if (Diagnose) + S.Diag(FI->getLocation(), diag::note_nontrivial_has_volatile_member) + << FI; + return false; + } + // Objective C ARC 4.3.5: // [...] nontrivally ownership-qualified types are [...] not trivially // default constructible, copy constructible, move constructible, copy @@ -6192,6 +6206,10 @@ // -- for all of the non-static data members of its class that are of class // type (or array thereof), each such class has a trivial [default // constructor or destructor] + // A copy/move [constructor or assignment operator] for a class X is + // trivial if + // -- class X has no non-static data members of volatile-qualified + // type, [...] if (!checkTrivialClassMembers(*this, RD, CSM, ConstArg, Diagnose)) return false; Index: test/CXX/class/class.union/p1.cpp =================================================================== --- test/CXX/class/class.union/p1.cpp +++ test/CXX/class/class.union/p1.cpp @@ -31,6 +31,10 @@ CopyAssign& operator=(CopyAssign& CA) { abort(); } }; +class Volatile { + volatile int a_; // expected-note {{because field 'a_' has volatile qualified type}} +}; + class Dtor { ~Dtor() { abort(); } // expected-note 2 {{because type 'Dtor' has a user-provided destructor}} expected-note 2{{here}} }; @@ -44,6 +48,7 @@ CopyCtor copyctor; // expected-error {{union member 'copyctor' has a non-trivial copy constructor}} CopyAssign copyassign; // expected-error {{union member 'copyassign' has a non-trivial copy assignment operator}} Dtor dtor; // expected-error {{union member 'dtor' has a non-trivial destructor}} + Volatile volatile_; // expected-error {{union member 'volatile_' has a non-trivial copy constructor}} Okay okay; }; Index: test/CXX/drs/dr4xx.cpp =================================================================== --- test/CXX/drs/dr4xx.cpp +++ test/CXX/drs/dr4xx.cpp @@ -1184,17 +1184,15 @@ long n2 = s2; } -namespace dr496 { // dr496: no +namespace dr496 { // dr496: 3.7 struct A { int n; }; struct B { volatile int n; }; int check1[ __is_trivially_copyable(const int) ? 1 : -1]; int check2[!__is_trivially_copyable(volatile int) ? 1 : -1]; int check3[ __is_trivially_constructible(A, const A&) ? 1 : -1]; - // FIXME: This is wrong. - int check4[ __is_trivially_constructible(B, const B&) ? 1 : -1]; + int check4[!__is_trivially_constructible(B, const B&) ? 1 : -1]; int check5[ __is_trivially_assignable(A, const A&) ? 1 : -1]; - // FIXME: This is wrong. - int check6[ __is_trivially_assignable(B, const B&) ? 1 : -1]; + int check6[!__is_trivially_assignable(B, const B&) ? 1 : -1]; } namespace dr497 { // dr497: yes Index: test/SemaCXX/type-traits.cpp =================================================================== --- test/SemaCXX/type-traits.cpp +++ test/SemaCXX/type-traits.cpp @@ -75,6 +75,9 @@ struct NonTrivialDefault { NonTrivialDefault(); }; +struct HasVolatileMember { + volatile int i; +}; struct HasDest { ~HasDest(); }; class HasPriv { int priv; }; @@ -1911,6 +1914,12 @@ { int arr[F((__is_trivially_constructible(class_forward[])))]; } { int arr[F((__is_trivially_constructible(void)))]; } + { int arr[T((__is_trivially_constructible(HasVolatileMember)))]; } + { int arr[F((__is_trivially_constructible(HasVolatileMember, + const HasVolatileMember &)))]; } + { int arr[F((__is_trivially_constructible(HasVolatileMember, + HasVolatileMember &&)))]; } + { int arr[T((__is_trivially_assignable(int&, int)))]; } { int arr[T((__is_trivially_assignable(int&, int&)))]; } { int arr[T((__is_trivially_assignable(int&, int&&)))]; } @@ -1951,6 +1960,11 @@ TrivialMoveButNotCopy)))]; } { int arr[T((__is_trivially_assignable(TrivialMoveButNotCopy&, TrivialMoveButNotCopy&&)))]; } + + { int arr[F((__is_trivially_assignable(HasVolatileMember, + const HasVolatileMember &)))]; } + { int arr[F((__is_trivially_assignable(HasVolatileMember, + HasVolatileMember &&)))]; } } void constructible_checks() {