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