summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/AST/DeclCXX.cpp18
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp3
-rw-r--r--clang/lib/Sema/SemaExpr.cpp11
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))
OpenPOWER on IntegriCloud