diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 1f5255dae7ff..9a31dd8ef872 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -3871,6 +3871,10 @@ void Sema::CheckExplicitlyDefaultedDefaultConstructor(CXXConstructorDecl *CD) { // FIXME: a compatible, but different, explicit exception specification // will be silently overridden. We should issue a warning if this happens. EPI.ExtInfo = CtorType->getExtInfo(); + + // Such a function is also trivial if the implicitly-declared function + // would have been. + CD->setTrivial(CD->getParent()->hasTrivialDefaultConstructor()); } if (HadError) { @@ -3966,6 +3970,10 @@ void Sema::CheckExplicitlyDefaultedCopyConstructor(CXXConstructorDecl *CD) { // -- [...] it shall have the same parameter type as if it had been // implicitly declared. CD->setType(Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI)); + + // Such a function is also trivial if the implicitly-declared function + // would have been. + CD->setTrivial(CD->getParent()->hasTrivialCopyConstructor()); } if (HadError) { @@ -4053,6 +4061,10 @@ void Sema::CheckExplicitlyDefaultedCopyAssignment(CXXMethodDecl *MD) { EPI.RefQualifier = OperType->getRefQualifier(); EPI.ExtInfo = OperType->getExtInfo(); MD->setType(Context.getFunctionType(ReturnType, &ArgType, 1, EPI)); + + // Such a function is also trivial if the implicitly-declared function + // would have been. + MD->setTrivial(MD->getParent()->hasTrivialCopyAssignment()); } if (HadError) { @@ -4146,6 +4158,10 @@ void Sema::CheckExplicitlyDefaultedMoveConstructor(CXXConstructorDecl *CD) { // -- [...] it shall have the same parameter type as if it had been // implicitly declared. CD->setType(Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI)); + + // Such a function is also trivial if the implicitly-declared function + // would have been. + CD->setTrivial(CD->getParent()->hasTrivialMoveConstructor()); } if (HadError) { @@ -4231,6 +4247,10 @@ void Sema::CheckExplicitlyDefaultedMoveAssignment(CXXMethodDecl *MD) { EPI.RefQualifier = OperType->getRefQualifier(); EPI.ExtInfo = OperType->getExtInfo(); MD->setType(Context.getFunctionType(ReturnType, &ArgType, 1, EPI)); + + // Such a function is also trivial if the implicitly-declared function + // would have been. + MD->setTrivial(MD->getParent()->hasTrivialMoveAssignment()); } if (HadError) { @@ -4278,6 +4298,10 @@ void Sema::CheckExplicitlyDefaultedDestructor(CXXDestructorDecl *DD) { // There are no parameters. EPI.ExtInfo = DtorType->getExtInfo(); DD->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI)); + + // Such a function is also trivial if the implicitly-declared function + // would have been. + DD->setTrivial(DD->getParent()->hasTrivialDestructor()); } if (ShouldDeleteSpecialMember(DD, CXXDestructor)) { @@ -10254,6 +10278,35 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) { // recovery. } Fn->setDeletedAsWritten(); + + CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Dcl); + if (!MD) + return; + + // A deleted special member function is trivial if the corresponding + // implicitly-declared function would have been. + switch (getSpecialMember(MD)) { + case CXXInvalid: + break; + case CXXDefaultConstructor: + MD->setTrivial(MD->getParent()->hasTrivialDefaultConstructor()); + break; + case CXXCopyConstructor: + MD->setTrivial(MD->getParent()->hasTrivialCopyConstructor()); + break; + case CXXMoveConstructor: + MD->setTrivial(MD->getParent()->hasTrivialMoveConstructor()); + break; + case CXXCopyAssignment: + MD->setTrivial(MD->getParent()->hasTrivialCopyAssignment()); + break; + case CXXMoveAssignment: + MD->setTrivial(MD->getParent()->hasTrivialMoveAssignment()); + break; + case CXXDestructor: + MD->setTrivial(MD->getParent()->hasTrivialDestructor()); + break; + } } void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) { diff --git a/clang/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp b/clang/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp index d401a97ca25c..06dd1bb05560 100644 --- a/clang/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp +++ b/clang/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp @@ -35,7 +35,8 @@ struct S3 { }; constexpr S3 s3a = S3(0); constexpr S3 s3b = s3a; -constexpr S3 s3c = S3(); // expected-error {{constant expression}} expected-note {{non-constexpr constructor}} +constexpr S3 s3c = S3(); +constexpr S3 s3d; // expected-error {{constant expression}} expected-note {{non-constexpr constructor}} struct S4 { S4() = default; diff --git a/clang/test/CXX/special/class.ctor/p5-0x.cpp b/clang/test/CXX/special/class.ctor/p5-0x.cpp index b2fa0cf29844..b81755dcd33e 100644 --- a/clang/test/CXX/special/class.ctor/p5-0x.cpp +++ b/clang/test/CXX/special/class.ctor/p5-0x.cpp @@ -25,10 +25,8 @@ union Deleted1a { UserProvidedDefCtor u; }; // expected-note {{defined here}} Deleted1a d1a; // expected-error {{implicitly-deleted default constructor}} union NotDeleted1a { DefaultedDefCtor1 nu; }; NotDeleted1a nd1a; -// FIXME: clang implements the pre-FDIS rule, under which DefaultedDefCtor2's -// default constructor is non-trivial. -union NotDeleted1b { DefaultedDefCtor2 nu; }; // unexpected-note {{defined here}} -NotDeleted1b nd1b; // unexpected-error {{implicitly-deleted default constructor}} +union NotDeleted1b { DefaultedDefCtor2 nu; }; +NotDeleted1b nd1b; // - any non-static data member with no brace-or-equal-initializer is of // reference type, @@ -170,4 +168,3 @@ static_assert(__has_trivial_constructor(Trivial4<int>), "Trivial4 is trivial"); template<typename T> class Trivial5 { Trivial5() = delete; }; static_assert(__has_trivial_constructor(Trivial5<int>), "Trivial5 is trivial"); - diff --git a/clang/test/CodeGenCXX/constructor-init.cpp b/clang/test/CodeGenCXX/constructor-init.cpp index 6af5188a41f6..9f808f6680ed 100644 --- a/clang/test/CodeGenCXX/constructor-init.cpp +++ b/clang/test/CodeGenCXX/constructor-init.cpp @@ -201,7 +201,7 @@ namespace PR10720 { pair2(const pair2&) = default; }; - struct pair { + struct pair : X { // Make the copy constructor non-trivial, so we actually generate it. int second[4]; // CHECK-PR10720: define linkonce_odr void @_ZN7PR107204pairC2ERKS0_ // CHECK-PR10720-NOT: ret @@ -220,4 +220,3 @@ namespace PR10720 { } } - diff --git a/clang/test/CodeGenCXX/pr9965.cpp b/clang/test/CodeGenCXX/pr9965.cpp index f625f48c33f6..0d267ff70372 100644 --- a/clang/test/CodeGenCXX/pr9965.cpp +++ b/clang/test/CodeGenCXX/pr9965.cpp @@ -1,6 +1,7 @@ // RUN: %clang_cc1 -std=c++11 -emit-llvm -o - %s | FileCheck %s +struct A { A(); }; template<typename T> -struct X +struct X : A // default constructor is not trivial { X() = default; ~X() {} // not a literal type diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp index fd41c17ab276..f53939ac1790 100644 --- a/clang/test/SemaCXX/type-traits.cpp +++ b/clang/test/SemaCXX/type-traits.cpp @@ -932,6 +932,41 @@ struct NonTCStruct { NonTCStruct(const NonTCStruct&) {} }; +struct AllDefaulted { + AllDefaulted() = default; + AllDefaulted(const AllDefaulted &) = default; + AllDefaulted(AllDefaulted &&) = default; + AllDefaulted &operator=(const AllDefaulted &) = default; + AllDefaulted &operator=(AllDefaulted &&) = default; + ~AllDefaulted() = default; +}; + +struct AllDeleted { + AllDeleted() = delete; + AllDeleted(const AllDeleted &) = delete; + AllDeleted(AllDeleted &&) = delete; + AllDeleted &operator=(const AllDeleted &) = delete; + AllDeleted &operator=(AllDeleted &&) = delete; + ~AllDeleted() = delete; +}; + +struct ExtDefaulted { + ExtDefaulted(); + ExtDefaulted(const ExtDefaulted &); + ExtDefaulted(ExtDefaulted &&); + ExtDefaulted &operator=(const ExtDefaulted &); + ExtDefaulted &operator=(ExtDefaulted &&); + ~ExtDefaulted(); +}; + +// Despite being defaulted, these functions are not trivial. +ExtDefaulted::ExtDefaulted() = default; +ExtDefaulted::ExtDefaulted(const ExtDefaulted &) = default; +ExtDefaulted::ExtDefaulted(ExtDefaulted &&) = default; +ExtDefaulted &ExtDefaulted::operator=(const ExtDefaulted &) = default; +ExtDefaulted &ExtDefaulted::operator=(ExtDefaulted &&) = default; +ExtDefaulted::~ExtDefaulted() = default; + void is_trivial2() { int t01[T(__is_trivial(char))]; @@ -956,11 +991,14 @@ void is_trivial2() int t20[T(__is_trivial(Union))]; int t21[T(__is_trivial(UnionAr))]; int t22[T(__is_trivial(TrivialStruct))]; + int t23[T(__is_trivial(AllDefaulted))]; + int t24[T(__is_trivial(AllDeleted))]; int t30[F(__is_trivial(void))]; int t31[F(__is_trivial(NonTrivialStruct))]; int t32[F(__is_trivial(SuperNonTrivialStruct))]; int t33[F(__is_trivial(NonTCStruct))]; + int t34[F(__is_trivial(ExtDefaulted))]; } void is_trivially_copyable2() @@ -988,10 +1026,13 @@ void is_trivially_copyable2() int t21[T(__is_trivially_copyable(UnionAr))]; int t22[T(__is_trivially_copyable(TrivialStruct))]; int t23[T(__is_trivially_copyable(NonTrivialStruct))]; + int t24[T(__is_trivially_copyable(AllDefaulted))]; + int t25[T(__is_trivially_copyable(AllDeleted))]; int t30[F(__is_trivially_copyable(void))]; - int t32[F(__is_trivially_copyable(SuperNonTrivialStruct))]; - int t31[F(__is_trivially_copyable(NonTCStruct))]; + int t31[F(__is_trivially_copyable(SuperNonTrivialStruct))]; + int t32[F(__is_trivially_copyable(NonTCStruct))]; + int t33[F(__is_trivially_copyable(ExtDefaulted))]; } struct CStruct { @@ -1147,6 +1188,8 @@ void has_trivial_default_constructor() { { int arr[T(__has_trivial_constructor(HasCopyAssign))]; } { int arr[T(__has_trivial_constructor(HasMoveAssign))]; } { int arr[T(__has_trivial_constructor(const Int))]; } + { int arr[T(__has_trivial_constructor(AllDefaulted))]; } + { int arr[T(__has_trivial_constructor(AllDeleted))]; } { int arr[F(__has_trivial_constructor(HasCons))]; } { int arr[F(__has_trivial_constructor(HasRef))]; } @@ -1157,6 +1200,7 @@ void has_trivial_default_constructor() { { int arr[F(__has_trivial_constructor(cvoid))]; } { int arr[F(__has_trivial_constructor(HasTemplateCons))]; } { int arr[F(__has_trivial_constructor(AllPrivate))]; } + { int arr[F(__has_trivial_constructor(ExtDefaulted))]; } } void has_trivial_copy_constructor() { @@ -1177,6 +1221,8 @@ void has_trivial_copy_constructor() { { int arr[T(__has_trivial_copy(HasCopyAssign))]; } { int arr[T(__has_trivial_copy(HasMoveAssign))]; } { int arr[T(__has_trivial_copy(const Int))]; } + { int arr[T(__has_trivial_copy(AllDefaulted))]; } + { int arr[T(__has_trivial_copy(AllDeleted))]; } { int arr[F(__has_trivial_copy(HasCopy))]; } { int arr[F(__has_trivial_copy(HasTemplateCons))]; } @@ -1185,6 +1231,7 @@ void has_trivial_copy_constructor() { { int arr[F(__has_trivial_copy(void))]; } { int arr[F(__has_trivial_copy(cvoid))]; } { int arr[F(__has_trivial_copy(AllPrivate))]; } + { int arr[F(__has_trivial_copy(ExtDefaulted))]; } } void has_trivial_copy_assignment() { @@ -1201,6 +1248,8 @@ void has_trivial_copy_assignment() { { int arr[T(__has_trivial_assign(HasCopy))]; } { int arr[T(__has_trivial_assign(HasMove))]; } { int arr[T(__has_trivial_assign(HasMoveAssign))]; } + { int arr[T(__has_trivial_assign(AllDefaulted))]; } + { int arr[T(__has_trivial_assign(AllDeleted))]; } { int arr[F(__has_trivial_assign(IntRef))]; } { int arr[F(__has_trivial_assign(HasCopyAssign))]; } @@ -1212,6 +1261,7 @@ void has_trivial_copy_assignment() { { int arr[F(__has_trivial_assign(void))]; } { int arr[F(__has_trivial_assign(cvoid))]; } { int arr[F(__has_trivial_assign(AllPrivate))]; } + { int arr[F(__has_trivial_assign(ExtDefaulted))]; } } void has_trivial_destructor() { @@ -1234,11 +1284,14 @@ void has_trivial_destructor() { { int arr[T(__has_trivial_destructor(const Int))]; } { int arr[T(__has_trivial_destructor(DerivesAr))]; } { int arr[T(__has_trivial_destructor(VirtAr))]; } + { int arr[T(__has_trivial_destructor(AllDefaulted))]; } + { int arr[T(__has_trivial_destructor(AllDeleted))]; } { int arr[F(__has_trivial_destructor(HasDest))]; } { int arr[F(__has_trivial_destructor(void))]; } { int arr[F(__has_trivial_destructor(cvoid))]; } { int arr[F(__has_trivial_destructor(AllPrivate))]; } + { int arr[F(__has_trivial_destructor(ExtDefaulted))]; } } struct A { ~A() {} }; @@ -1460,13 +1513,11 @@ void is_base_of() { isBaseOfF<DerivedB<int>, BaseA<int> >(); } -#if 0 template<class T, class U> class TemplateClass {}; template<class T> using TemplateAlias = TemplateClass<T, int>; -#endif typedef class Base BaseTypedef; @@ -1474,9 +1525,7 @@ void is_same() { int t01[T(__is_same(Base, Base))]; int t02[T(__is_same(Base, BaseTypedef))]; -#if 0 int t03[T(__is_same(TemplateClass<int, int>, TemplateAlias<int>))]; -#endif int t10[F(__is_same(Base, const Base))]; int t11[F(__is_same(Base, Base&))]; @@ -1668,10 +1717,25 @@ void trivial_checks() const NonTrivialDefault&)))]; } { int arr[T((__is_trivially_constructible(NonTrivialDefault, NonTrivialDefault&&)))]; } + { int arr[T((__is_trivially_constructible(AllDefaulted)))]; } + { int arr[T((__is_trivially_constructible(AllDefaulted, + const AllDefaulted &)))]; } + { int arr[T((__is_trivially_constructible(AllDefaulted, + AllDefaulted &&)))]; } { int arr[F((__is_trivially_constructible(int, int*)))]; } { int arr[F((__is_trivially_constructible(NonTrivialDefault)))]; } { int arr[F((__is_trivially_constructible(ThreeArgCtor, int*, char*, int&)))]; } + { int arr[F((__is_trivially_constructible(AllDeleted)))]; } + { int arr[F((__is_trivially_constructible(AllDeleted, + const AllDeleted &)))]; } + { int arr[F((__is_trivially_constructible(AllDeleted, + AllDeleted &&)))]; } + { int arr[F((__is_trivially_constructible(ExtDefaulted)))]; } + { int arr[F((__is_trivially_constructible(ExtDefaulted, + const ExtDefaulted &)))]; } + { int arr[F((__is_trivially_constructible(ExtDefaulted, + ExtDefaulted &&)))]; } { int arr[T((__is_trivially_assignable(int&, int)))]; } { int arr[T((__is_trivially_assignable(int&, int&)))]; } @@ -1682,6 +1746,10 @@ void trivial_checks() { int arr[T((__is_trivially_assignable(POD&, POD&&)))]; } { int arr[T((__is_trivially_assignable(POD&, const POD&)))]; } { int arr[T((__is_trivially_assignable(int*&, int*)))]; } + { int arr[T((__is_trivially_assignable(AllDefaulted, + const AllDefaulted &)))]; } + { int arr[T((__is_trivially_assignable(AllDefaulted, + AllDefaulted &&)))]; } { int arr[F((__is_trivially_assignable(int*&, float*)))]; } { int arr[F((__is_trivially_assignable(HasCopyAssign&, HasCopyAssign)))]; } @@ -1692,18 +1760,22 @@ void trivial_checks() TrivialMoveButNotCopy&)))]; } { int arr[F((__is_trivially_assignable(TrivialMoveButNotCopy&, const TrivialMoveButNotCopy&)))]; } + { int arr[F((__is_trivially_assignable(AllDeleted, + const AllDeleted &)))]; } + { int arr[F((__is_trivially_assignable(AllDeleted, + AllDeleted &&)))]; } + { int arr[F((__is_trivially_assignable(ExtDefaulted, + const ExtDefaulted &)))]; } + { int arr[F((__is_trivially_assignable(ExtDefaulted, + ExtDefaulted &&)))]; } - // FIXME: The following answers are wrong, because we don't properly - // mark user-declared constructors/assignment operators/destructors - // that are defaulted on their first declaration as trivial when we - // can. - { int arr[F((__is_trivially_assignable(HasDefaultTrivialCopyAssign&, + { int arr[T((__is_trivially_assignable(HasDefaultTrivialCopyAssign&, HasDefaultTrivialCopyAssign&)))]; } - { int arr[F((__is_trivially_assignable(HasDefaultTrivialCopyAssign&, + { int arr[T((__is_trivially_assignable(HasDefaultTrivialCopyAssign&, const HasDefaultTrivialCopyAssign&)))]; } - { int arr[F((__is_trivially_assignable(TrivialMoveButNotCopy&, + { int arr[T((__is_trivially_assignable(TrivialMoveButNotCopy&, TrivialMoveButNotCopy)))]; } - { int arr[F((__is_trivially_assignable(TrivialMoveButNotCopy&, + { int arr[T((__is_trivially_assignable(TrivialMoveButNotCopy&, TrivialMoveButNotCopy&&)))]; } }