r343279 - [cxx2a] P0624R2: Lambdas with no capture-default are
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Thu Sep 27 15:47:05 PDT 2018
Author: rsmith
Date: Thu Sep 27 15:47:04 2018
New Revision: 343279
URL: http://llvm.org/viewvc/llvm-project?rev=343279&view=rev
Log:
[cxx2a] P0624R2: Lambdas with no capture-default are
default-constructible and assignable.
Added:
cfe/trunk/test/SemaCXX/cxx2a-lambda-default-ctor-assign.cpp
Modified:
cfe/trunk/include/clang/AST/DeclCXX.h
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/lib/AST/DeclCXX.cpp
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/lib/Sema/SemaExpr.cpp
cfe/trunk/test/SemaCXX/cxx17-compat.cpp
cfe/trunk/www/cxx_status.html
Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=343279&r1=343278&r2=343279&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Thu Sep 27 15:47:04 2018
@@ -974,10 +974,7 @@ public:
bool needsImplicitDefaultConstructor() const {
return !data().UserDeclaredConstructor &&
!(data().DeclaredSpecialMembers & SMF_DefaultConstructor) &&
- // C++14 [expr.prim.lambda]p20:
- // The closure type associated with a lambda-expression has no
- // default constructor.
- !isLambda();
+ (!isLambda() || lambdaIsDefaultConstructibleAndAssignable());
}
/// Determine whether this class has any user-declared constructors.
@@ -1167,10 +1164,7 @@ public:
!hasUserDeclaredCopyAssignment() &&
!hasUserDeclaredMoveConstructor() &&
!hasUserDeclaredDestructor() &&
- // C++1z [expr.prim.lambda]p21: "the closure type has a deleted copy
- // assignment operator". The intent is that this counts as a user
- // declared copy assignment, but we do not model it that way.
- !isLambda();
+ (!isLambda() || lambdaIsDefaultConstructibleAndAssignable());
}
/// Determine whether we need to eagerly declare a move assignment
@@ -1210,6 +1204,10 @@ public:
/// a template).
bool isGenericLambda() const;
+ /// Determine whether this lambda should have an implicit default constructor
+ /// and copy and move assignment operators.
+ bool lambdaIsDefaultConstructibleAndAssignable() const;
+
/// Retrieve the lambda call operator of the closure type
/// if this is a closure type.
CXXMethodDecl *getLambdaCallOperator() const;
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=343279&r1=343278&r2=343279&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Sep 27 15:47:04 2018
@@ -6633,6 +6633,11 @@ let CategoryName = "Lambda Issue" in {
InGroup<DeprecatedThisCapture>, DefaultIgnore;
def note_deprecated_this_capture : Note<
"add an explicit capture of 'this' to capture '*this' by reference">;
+
+ // C++2a default constructible / assignable lambdas.
+ def warn_cxx17_compat_lambda_def_ctor_assign : Warning<
+ "%select{default construction|assignment}0 of lambda is incompatible with "
+ "C++ standards before C++2a">, InGroup<CXXPre2aCompat>, DefaultIgnore;
}
def err_return_in_captured_stmt : Error<
Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=343279&r1=343278&r2=343279&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Thu Sep 27 15:47:04 2018
@@ -628,6 +628,24 @@ bool CXXRecordDecl::hasSubobjectAtOffset
return false;
}
+bool CXXRecordDecl::lambdaIsDefaultConstructibleAndAssignable() const {
+ assert(isLambda() && "not a lambda");
+
+ // C++2a [expr.prim.lambda.capture]p11:
+ // The closure type associated with a lambda-expression has no default
+ // constructor if the lambda-expression has a lambda-capture and a
+ // defaulted default constructor otherwise. It has a deleted copy
+ // assignment operator if the lambda-expression has a lambda-capture and
+ // defaulted copy and move assignment operators otherwise.
+ //
+ // C++17 [expr.prim.lambda]p21:
+ // The closure type associated with a lambda-expression has no default
+ // constructor and a deleted copy assignment operator.
+ if (getLambdaCaptureDefault() != LCD_None)
+ return false;
+ return getASTContext().getLangOpts().CPlusPlus2a;
+}
+
void CXXRecordDecl::addedMember(Decl *D) {
if (!D->isImplicit() &&
!isa<FieldDecl>(D) &&
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=343279&r1=343278&r2=343279&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Thu Sep 27 15:47:04 2018
@@ -7088,7 +7088,8 @@ bool Sema::ShouldDeleteSpecialMember(CXX
// The closure type associated with a lambda-expression has a
// deleted (8.4.3) default constructor and a deleted copy
// assignment operator.
- if (RD->isLambda() &&
+ // C++2a adds back these operators if the lambda has no capture-default.
+ if (RD->isLambda() && !RD->lambdaIsDefaultConstructibleAndAssignable() &&
(CSM == CXXDefaultConstructor || CSM == CXXCopyAssignment)) {
if (Diagnose)
Diag(RD->getLocation(), diag::note_lambda_decl);
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=343279&r1=343278&r2=343279&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Thu Sep 27 15:47:04 2018
@@ -266,6 +266,17 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *
return true;
}
+ if (auto *MD = dyn_cast<CXXMethodDecl>(D)) {
+ // Lambdas are only default-constructible or assignable in C++2a onwards.
+ if (MD->getParent()->isLambda() &&
+ ((isa<CXXConstructorDecl>(MD) &&
+ cast<CXXConstructorDecl>(MD)->isDefaultConstructor()) ||
+ MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator())) {
+ Diag(Loc, diag::warn_cxx17_compat_lambda_def_ctor_assign)
+ << !isa<CXXConstructorDecl>(MD);
+ }
+ }
+
auto getReferencedObjCProp = [](const NamedDecl *D) ->
const ObjCPropertyDecl * {
if (const auto *MD = dyn_cast<ObjCMethodDecl>(D))
Modified: cfe/trunk/test/SemaCXX/cxx17-compat.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx17-compat.cpp?rev=343279&r1=343278&r2=343279&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx17-compat.cpp (original)
+++ cfe/trunk/test/SemaCXX/cxx17-compat.cpp Thu Sep 27 15:47:04 2018
@@ -27,3 +27,18 @@ struct B {
// expected-warning at -4 {{default member initializer for bit-field is incompatible with C++ standards before C++2a}}
#endif
};
+
+auto Lambda = []{};
+decltype(Lambda) AnotherLambda;
+#if __cplusplus <= 201703L
+ // expected-error at -2 {{no matching constructor}} expected-note at -3 2{{candidate}}
+#else
+ // expected-warning at -4 {{default construction of lambda is incompatible with C++ standards before C++2a}}
+#endif
+
+void copy_lambda() { Lambda = Lambda; }
+#if __cplusplus <= 201703L
+ // expected-error at -2 {{deleted}} expected-note at -10 {{lambda}}
+#else
+ // expected-warning at -4 {{assignment of lambda is incompatible with C++ standards before C++2a}}
+#endif
Added: cfe/trunk/test/SemaCXX/cxx2a-lambda-default-ctor-assign.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx2a-lambda-default-ctor-assign.cpp?rev=343279&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx2a-lambda-default-ctor-assign.cpp (added)
+++ cfe/trunk/test/SemaCXX/cxx2a-lambda-default-ctor-assign.cpp Thu Sep 27 15:47:04 2018
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -std=c++2a -verify %s
+
+auto a = []{};
+decltype(a) a2;
+void f(decltype(a) x, decltype(a) y) {
+ x = y;
+ x = static_cast<decltype(a)&&>(y);
+}
+
+template<typename T>
+struct X {
+ constexpr X() { T::error; } // expected-error {{'::'}}
+ X(const X&);
+ constexpr X &operator=(const X&) { T::error; } // expected-error {{'::'}}
+ constexpr X &operator=(X&&) { T::error; } // expected-error {{'::'}}
+};
+extern X<int> x;
+auto b = [x = x]{}; // expected-note 3{{in instantiation of}}
+decltype(b) b2; // expected-note {{in implicit default constructor}}
+void f(decltype(b) x, decltype(b) y) {
+ x = y; // expected-note {{in implicit copy assignment}}
+ x = static_cast<decltype(b)&&>(y); // expected-note {{in implicit move assignment}}
+}
+
+struct Y {
+ Y() = delete; // expected-note {{deleted}}
+ Y(const Y&);
+ Y &operator=(const Y&) = delete; // expected-note 2{{deleted}}
+ Y &operator=(Y&&) = delete;
+};
+extern Y y;
+auto c = [y = y]{}; // expected-note 3{{deleted because}}
+decltype(c) c2; // expected-error {{deleted}}
+void f(decltype(c) x, decltype(c) y) {
+ x = y; // expected-error {{deleted}}
+ x = static_cast<decltype(c)&&>(y); // expected-error {{deleted}}
+}
Modified: cfe/trunk/www/cxx_status.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_status.html?rev=343279&r1=343278&r2=343279&view=diff
==============================================================================
--- cfe/trunk/www/cxx_status.html (original)
+++ cfe/trunk/www/cxx_status.html Thu Sep 27 15:47:04 2018
@@ -905,7 +905,7 @@ as the draft C++2a standard evolves.
<tr>
<td>Default constructible and assignable stateless lambdas</td>
<td><a href="http://wg21.link/p0624r2">P0624R2</a></td>
- <td class="none" align="center">No</td>
+ <td class="svn" align="center">SVN</td>
</tr>
<tr>
<td>Lambdas in unevaluated contexts</td>
More information about the cfe-commits
mailing list