Implement the suggested resolution of WG21 N3307 issue 19: When determining whether a class is an aggregate in C++0x, treat all functions which are neither deleted nor defaulted as user-provided, not just special member functions. The wording of the standard only defines the term "user-provided" for special member functions, but the intent seems to be that any function can be user-provided.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@139111 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index be529f8..1821ba8 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -503,18 +503,18 @@
// Note that we have a user-declared constructor.
data().UserDeclaredConstructor = true;
- // FIXME: Under C++0x, /only/ special member functions may be user-provided.
- // This is probably a defect.
- bool UserProvided = false;
+ // Technically, "user-provided" is only defined for special member
+ // functions, but the intent of the standard is clearly that it should apply
+ // to all functions.
+ bool UserProvided = Constructor->isUserProvided();
// C++0x [class.ctor]p5:
// A default constructor is trivial if it is not user-provided [...]
if (Constructor->isDefaultConstructor()) {
data().DeclaredDefaultConstructor = true;
- if (Constructor->isUserProvided()) {
+ if (UserProvided) {
data().HasTrivialDefaultConstructor = false;
data().UserProvidedDefaultConstructor = true;
- UserProvided = true;
}
}
@@ -528,10 +528,8 @@
// C++0x [class.copy]p13:
// A copy/move constructor for class X is trivial if it is not
// user-provided [...]
- if (Constructor->isUserProvided()) {
+ if (UserProvided)
data().HasTrivialCopyConstructor = false;
- UserProvided = true;
- }
} else if (Constructor->isMoveConstructor()) {
data().UserDeclaredMoveConstructor = true;
data().DeclaredMoveConstructor = true;
@@ -539,10 +537,8 @@
// C++0x [class.copy]p13:
// A copy/move constructor for class X is trivial if it is not
// user-provided [...]
- if (Constructor->isUserProvided()) {
+ if (UserProvided)
data().HasTrivialMoveConstructor = false;
- UserProvided = true;
- }
}
}
if (Constructor->isConstexpr() && !Constructor->isCopyOrMoveConstructor()) {
diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp
index 9b92340..1463133 100644
--- a/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp
+++ b/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp
@@ -18,11 +18,10 @@
NonAggr1a(int, int);
int k;
};
-// In C++03, this is {{non-aggregate type 'NonAggr1a'}}.
// In C++0x, 'user-provided' is only defined for special member functions, so
-// this type is considered to be an aggregate. This is probably a langauge
-// defect.
-NonAggr1a na1a = { 42 };
+// this type is considered to be an aggregate. This is considered to be
+// a language defect.
+NonAggr1a na1a = { 42 }; // expected-error {{non-aggregate type 'NonAggr1a'}}
struct NonAggr1b {
NonAggr1b(const NonAggr1b &);
diff --git a/test/SemaCXX/aggregate-initialization.cpp b/test/SemaCXX/aggregate-initialization.cpp
index b9e69b0..90d0ead 100644
--- a/test/SemaCXX/aggregate-initialization.cpp
+++ b/test/SemaCXX/aggregate-initialization.cpp
@@ -2,8 +2,8 @@
// Verify that we can't initialize non-aggregates with an initializer
// list.
-// FIXME: Note that due to a (likely) standard bug, this is technically an
-// aggregate.
+// Note that due to a (likely) standard bug, this is technically an aggregate,
+// but we do not treat it as one.
struct NonAggr1 {
NonAggr1(int) { }
@@ -24,7 +24,7 @@
virtual void f();
};
-NonAggr1 na1 = { 17 };
+NonAggr1 na1 = { 17 }; // expected-error{{non-aggregate type 'NonAggr1' cannot be initialized with an initializer list}}
NonAggr2 na2 = { 17 }; // expected-error{{non-aggregate type 'NonAggr2' cannot be initialized with an initializer list}}
NonAggr3 na3 = { 17 }; // expected-error{{non-aggregate type 'NonAggr3' cannot be initialized with an initializer list}}
NonAggr4 na4 = { 17 }; // expected-error{{non-aggregate type 'NonAggr4' cannot be initialized with an initializer list}}