summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/Basic/DiagnosticSemaKinds.td3
-rw-r--r--clang/lib/AST/DeclCXX.cpp11
-rw-r--r--clang/lib/Sema/SemaInit.cpp35
-rw-r--r--clang/test/SemaCXX/cxx2a-compat.cpp23
-rw-r--r--clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp23
-rwxr-xr-xclang/www/cxx_status.html2
6 files changed, 90 insertions, 7 deletions
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 6f0014ce186..5ec3e5ceae8 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1872,6 +1872,9 @@ def err_reference_bind_init_list : Error<
def err_init_list_bad_dest_type : Error<
"%select{|non-aggregate }0type %1 cannot be initialized with an initializer "
"list">;
+def warn_cxx2a_compat_aggregate_init_with_ctors : Warning<
+ "aggregate initialization of type %0 with user-declared constructors "
+ "is incompatible with C++2a">, DefaultIgnore, InGroup<CXX2aCompat>;
def err_reference_bind_to_bitfield : Error<
"%select{non-const|volatile}0 reference cannot bind to "
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 5c708694913..00ae7c9cda1 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -731,9 +731,14 @@ void CXXRecordDecl::addedMember(Decl *D) {
}
// C++11 [dcl.init.aggr]p1: DR1518
- // An aggregate is an array or a class with no user-provided, explicit, or
- // inherited constructors
- if (Constructor->isUserProvided() || Constructor->isExplicit())
+ // An aggregate is an array or a class with no user-provided [or]
+ // explicit [...] constructors
+ // C++20 [dcl.init.aggr]p1:
+ // An aggregate is an array or a class with no user-declared [...]
+ // constructors
+ if (getASTContext().getLangOpts().CPlusPlus2a
+ ? !Constructor->isImplicit()
+ : (Constructor->isUserProvided() || Constructor->isExplicit()))
data().Aggregate = false;
}
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index a25818f0fd3..a678a31a5ac 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -964,6 +964,14 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity,
StructuredSubobjectInitList->getEndLoc()),
"}");
}
+
+ // Warn if this type won't be an aggregate in future versions of C++.
+ auto *CXXRD = T->getAsCXXRecordDecl();
+ if (CXXRD && CXXRD->hasUserDeclaredConstructor()) {
+ SemaRef.Diag(StructuredSubobjectInitList->getBeginLoc(),
+ diag::warn_cxx2a_compat_aggregate_init_with_ctors)
+ << StructuredSubobjectInitList->getSourceRange() << T;
+ }
}
}
@@ -1106,9 +1114,30 @@ void InitListChecker::CheckExplicitInitList(const InitializedEntity &Entity,
}
}
- if (!VerifyOnly && T->isScalarType() &&
- IList->getNumInits() == 1 && !isa<InitListExpr>(IList->getInit(0)))
- warnBracedScalarInit(SemaRef, Entity, IList->getSourceRange());
+ if (!VerifyOnly) {
+ if (T->isScalarType() && IList->getNumInits() == 1 &&
+ !isa<InitListExpr>(IList->getInit(0)))
+ warnBracedScalarInit(SemaRef, Entity, IList->getSourceRange());
+
+ // Warn if this is a class type that won't be an aggregate in future
+ // versions of C++.
+ auto *CXXRD = T->getAsCXXRecordDecl();
+ if (CXXRD && CXXRD->hasUserDeclaredConstructor()) {
+ // Don't warn if there's an equivalent default constructor that would be
+ // used instead.
+ bool HasEquivCtor = false;
+ if (IList->getNumInits() == 0) {
+ auto *CD = SemaRef.LookupDefaultConstructor(CXXRD);
+ HasEquivCtor = CD && !CD->isDeleted();
+ }
+
+ if (!HasEquivCtor) {
+ SemaRef.Diag(IList->getBeginLoc(),
+ diag::warn_cxx2a_compat_aggregate_init_with_ctors)
+ << IList->getSourceRange() << T;
+ }
+ }
+ }
}
void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity,
diff --git a/clang/test/SemaCXX/cxx2a-compat.cpp b/clang/test/SemaCXX/cxx2a-compat.cpp
new file mode 100644
index 00000000000..53043d67fb8
--- /dev/null
+++ b/clang/test/SemaCXX/cxx2a-compat.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++17 -Wc++2a-compat-pedantic -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++2a -pedantic -verify %s
+
+struct A { // expected-note 0+{{candidate}}
+ A() = default; // expected-note 0+{{candidate}}
+ int x, y;
+};
+A a1 = {1, 2};
+#if __cplusplus <= 201703L
+ // expected-warning@-2 {{aggregate initialization of type 'A' with user-declared constructors is incompatible with C++2a}}
+#else
+ // expected-error@-4 {{no matching constructor}}
+#endif
+A a2 = {};
+
+struct B : A { A a; };
+B b1 = {{}, {}}; // ok
+B b2 = {1, 2, 3, 4};
+#if __cplusplus <= 201703L
+ // expected-warning@-2 2{{aggregate initialization of type 'A' with user-declared constructors is incompatible with C++2a}}
+#else
+ // expected-error@-4 2{{no viable conversion from 'int' to 'A'}}
+#endif
diff --git a/clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp b/clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp
new file mode 100644
index 00000000000..9c438d399b3
--- /dev/null
+++ b/clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -std=c++2a %s -verify
+
+namespace class_with_ctor {
+ struct A { // expected-note 6{{candidate}}
+ A() = default; // expected-note 3{{candidate}}
+ int x;
+ int y;
+ };
+ A a = {1, 2}; // expected-error {{no matching constructor}}
+
+ struct B {
+ int x;
+ int y;
+ };
+ B b1 = B(); // trigger declaration of implicit ctors
+ B b2 = {1, 2}; // ok
+
+ struct C : A {
+ A a;
+ };
+ C c1 = {{}, {}}; // ok, call default ctor twice
+ C c2 = {{1, 2}, {3, 4}}; // expected-error 2{{no matching constructor}}
+}
diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html
index 0d0add1584c..3ba8c9c7d0f 100755
--- a/clang/www/cxx_status.html
+++ b/clang/www/cxx_status.html
@@ -952,7 +952,7 @@ as the draft C++2a standard evolves.
<tr>
<td>Prohibit aggregates with user-declared constructors</td>
<td><a href="http://wg21.link/p1008r1">P1008R1</a></td>
- <td class="none" align="center">No</td>
+ <td class="svn" align="center">SVN</td>
</tr>
<tr>
<td>Contracts</td>
OpenPOWER on IntegriCloud