summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2012-02-26 00:31:33 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2012-02-26 00:31:33 +0000
commite653ba2f3b6d993b5d410554c12416c03ec7775b (patch)
tree345c722af33e56f43120a79253a4cd45003d94f6
parent2fa975c94027c6565cb112ffcf93c05b22922c0e (diff)
Special members which are defaulted or deleted on their first declaration are
trivial if the implicit declaration would be. Don't forget to set the Trivial flag on the special member as well as on the class. It doesn't seem ideal that we have two separate mechanisms for storing this information, but this patch does not attempt to address that. This leaves us in an interesting position where the has_trivial_X trait for a class says 'yes' for a deleted but trivial X, but is_trivially_Xable says 'no'. This seems to be what the standard requires. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@151465 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Sema/SemaDeclCXX.cpp53
-rw-r--r--test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp3
-rw-r--r--test/CXX/special/class.ctor/p5-0x.cpp7
-rw-r--r--test/CodeGenCXX/constructor-init.cpp3
-rw-r--r--test/CodeGenCXX/pr9965.cpp3
-rw-r--r--test/SemaCXX/type-traits.cpp102
6 files changed, 147 insertions, 24 deletions
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 1f5255dae7..9a31dd8ef8 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/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/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp b/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp
index d401a97ca2..06dd1bb055 100644
--- a/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp
+++ b/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/test/CXX/special/class.ctor/p5-0x.cpp b/test/CXX/special/class.ctor/p5-0x.cpp
index b2fa0cf298..b81755dcd3 100644
--- a/test/CXX/special/class.ctor/p5-0x.cpp
+++ b/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/test/CodeGenCXX/constructor-init.cpp b/test/CodeGenCXX/constructor-init.cpp
index 6af5188a41..9f808f6680 100644
--- a/test/CodeGenCXX/constructor-init.cpp
+++ b/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/test/CodeGenCXX/pr9965.cpp b/test/CodeGenCXX/pr9965.cpp
index f625f48c33..0d267ff703 100644
--- a/test/CodeGenCXX/pr9965.cpp
+++ b/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/test/SemaCXX/type-traits.cpp b/test/SemaCXX/type-traits.cpp
index fd41c17ab2..f53939ac17 100644
--- a/test/SemaCXX/type-traits.cpp
+++ b/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&)))]; }
-
- // 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[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 &&)))]; }
+
+ { 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&&)))]; }
}