Excellent, excellent - thanks! On Mon, Oct 1, 2018 at 10:22 AM Richard Smith <rich...@metafoo.co.uk> wrote:
> On Mon, 1 Oct 2018, 09:55 David Blaikie via cfe-commits, < > cfe-commits@lists.llvm.org> wrote: > >> Awesome - should/does this mean stateless lambdas can be used in >> uninitialized contexts? >> >> std::set<foo, decltype([](const foo& LHS, const foo& RHS) { return ...; >> })> s; >> >> Would be kind of neat/handy (so you didn't have to pass in the comparator >> on construction, etc) >> > > Not quite: that also needs p0315r4, but that's coming in C++20 too. > > On Thu, Sep 27, 2018 at 3:48 PM Richard Smith via cfe-commits < >> cfe-commits@lists.llvm.org> wrote: >> >>> 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@-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@-2 {{no matching constructor}} expected-note@-3 >>> 2{{candidate}} >>> +#else >>> + // expected-warning@-4 {{default construction of lambda is >>> incompatible with C++ standards before C++2a}} >>> +#endif >>> + >>> +void copy_lambda() { Lambda = Lambda; } >>> +#if __cplusplus <= 201703L >>> + // expected-error@-2 {{deleted}} expected-note@-10 {{lambda}} >>> +#else >>> + // expected-warning@-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> >>> >>> >>> _______________________________________________ >>> cfe-commits mailing list >>> cfe-commits@lists.llvm.org >>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits >>> >> _______________________________________________ >> cfe-commits mailing list >> cfe-commits@lists.llvm.org >> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits >> >
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits