diff options
Diffstat (limited to 'clang/lib')
| -rw-r--r-- | clang/lib/AST/DeclCXX.cpp | 18 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 3 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 11 |
3 files changed, 31 insertions, 1 deletions
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index 00ae7c9cda1..9bb6e3a013a 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -628,6 +628,24 @@ bool CXXRecordDecl::hasSubobjectAtOffsetZeroOfEmptyBaseType( 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) && diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index b81e5be56a2..a18b8dd5967 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -7088,7 +7088,8 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM, // 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); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index e89e8a2e68f..26fb107688f 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -266,6 +266,17 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs, 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)) |

