diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index 3a400a778e53a..856717fa0abb5 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -999,6 +999,9 @@ class CXXRecordDecl : public RecordDecl { return static_cast(getLambdaData().CaptureDefault); } + /// Set the captures for this lambda closure type. + void setCaptures(ArrayRef Captures); + /// For a closure type, retrieve the mapping from captured /// variables and \c this to the non-static data members that store the /// values or references of the captures. @@ -1030,6 +1033,8 @@ class CXXRecordDecl : public RecordDecl { : nullptr; } + unsigned capture_size() const { return getLambdaData().NumCaptures; } + using conversion_iterator = UnresolvedSetIterator; conversion_iterator conversion_begin() const { diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h index 272ad138d14a5..56b27d57bd5c8 100644 --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -1862,10 +1862,9 @@ class LambdaExpr final : public Expr, /// Construct a lambda expression. LambdaExpr(QualType T, SourceRange IntroducerRange, LambdaCaptureDefault CaptureDefault, - SourceLocation CaptureDefaultLoc, ArrayRef Captures, - bool ExplicitParams, bool ExplicitResultType, - ArrayRef CaptureInits, SourceLocation ClosingBrace, - bool ContainsUnexpandedParameterPack); + SourceLocation CaptureDefaultLoc, bool ExplicitParams, + bool ExplicitResultType, ArrayRef CaptureInits, + SourceLocation ClosingBrace, bool ContainsUnexpandedParameterPack); /// Construct an empty lambda expression. LambdaExpr(EmptyShell Empty, unsigned NumCaptures) @@ -1888,9 +1887,9 @@ class LambdaExpr final : public Expr, static LambdaExpr * Create(const ASTContext &C, CXXRecordDecl *Class, SourceRange IntroducerRange, LambdaCaptureDefault CaptureDefault, SourceLocation CaptureDefaultLoc, - ArrayRef Captures, bool ExplicitParams, - bool ExplicitResultType, ArrayRef CaptureInits, - SourceLocation ClosingBrace, bool ContainsUnexpandedParameterPack); + bool ExplicitParams, bool ExplicitResultType, + ArrayRef CaptureInits, SourceLocation ClosingBrace, + bool ContainsUnexpandedParameterPack); /// Construct a new lambda expression that will be deserialized from /// an external source. diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 10035162299e3..a2a712e6b6cad 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -1890,6 +1890,19 @@ Error ASTNodeImporter::ImportDefinition( // set in CXXRecordDecl::CreateLambda. We must import the contained // decls here and finish the definition. (To->isLambda() && shouldForceImportDeclContext(Kind))) { + if (To->isLambda()) { + auto *FromCXXRD = cast(From); + SmallVector ToCaptures; + ToCaptures.reserve(FromCXXRD->capture_size()); + for (const auto &FromCapture : FromCXXRD->captures()) { + if (auto ToCaptureOrErr = import(FromCapture)) + ToCaptures.push_back(*ToCaptureOrErr); + else + return ToCaptureOrErr.takeError(); + } + cast(To)->setCaptures(ToCaptures); + } + Error Result = ImportDeclContext(From, /*ForceImport=*/true); // Finish the definition of the lambda, set isBeingDefined to false. if (To->isLambda()) @@ -7588,15 +7601,6 @@ ExpectedStmt ASTNodeImporter::VisitLambdaExpr(LambdaExpr *E) { if (!ToCallOpOrErr) return ToCallOpOrErr.takeError(); - SmallVector ToCaptures; - ToCaptures.reserve(E->capture_size()); - for (const auto &FromCapture : E->captures()) { - if (auto ToCaptureOrErr = import(FromCapture)) - ToCaptures.push_back(*ToCaptureOrErr); - else - return ToCaptureOrErr.takeError(); - } - SmallVector ToCaptureInits(E->capture_size()); if (Error Err = ImportContainerChecked(E->capture_inits(), ToCaptureInits)) return std::move(Err); @@ -7608,11 +7612,11 @@ ExpectedStmt ASTNodeImporter::VisitLambdaExpr(LambdaExpr *E) { if (Err) return std::move(Err); - return LambdaExpr::Create( - Importer.getToContext(), ToClass, ToIntroducerRange, - E->getCaptureDefault(), ToCaptureDefaultLoc, ToCaptures, - E->hasExplicitParameters(), E->hasExplicitResultType(), ToCaptureInits, - ToEndLoc, E->containsUnexpandedParameterPack()); + return LambdaExpr::Create(Importer.getToContext(), ToClass, ToIntroducerRange, + E->getCaptureDefault(), ToCaptureDefaultLoc, + E->hasExplicitParameters(), + E->hasExplicitResultType(), ToCaptureInits, + ToEndLoc, E->containsUnexpandedParameterPack()); } diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index 5412aa7ed5e04..4d184b5a47033 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -664,8 +664,7 @@ bool CXXRecordDecl::lambdaIsDefaultConstructibleAndAssignable() const { // 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 || - getLambdaData().NumCaptures != 0) + if (getLambdaCaptureDefault() != LCD_None || capture_size() != 0) return false; return getASTContext().getLangOpts().CPlusPlus20; } @@ -1367,6 +1366,24 @@ void CXXRecordDecl::finishedDefaultedOrDeletedMember(CXXMethodDecl *D) { data().DeclaredNonTrivialSpecialMembers |= SMKind; } +void CXXRecordDecl::setCaptures(ArrayRef Captures) { + ASTContext &Context = getASTContext(); + CXXRecordDecl::LambdaDefinitionData &Data = getLambdaData(); + + // Copy captures. + Data.NumCaptures = Captures.size(); + Data.NumExplicitCaptures = 0; + Data.Captures = (LambdaCapture *)Context.Allocate(sizeof(LambdaCapture) * + Captures.size()); + LambdaCapture *ToCapture = Data.Captures; + for (unsigned I = 0, N = Captures.size(); I != N; ++I) { + if (Captures[I].isExplicit()) + ++Data.NumExplicitCaptures; + + *ToCapture++ = Captures[I]; + } +} + void CXXRecordDecl::setTrivialForCallFlags(CXXMethodDecl *D) { unsigned SMKind = 0; diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp index cfbf2c88c4cca..2b148b4fa7683 100644 --- a/clang/lib/AST/ExprCXX.cpp +++ b/clang/lib/AST/ExprCXX.cpp @@ -1087,35 +1087,18 @@ LambdaCaptureKind LambdaCapture::getCaptureKind() const { LambdaExpr::LambdaExpr(QualType T, SourceRange IntroducerRange, LambdaCaptureDefault CaptureDefault, - SourceLocation CaptureDefaultLoc, - ArrayRef Captures, bool ExplicitParams, + SourceLocation CaptureDefaultLoc, bool ExplicitParams, bool ExplicitResultType, ArrayRef CaptureInits, SourceLocation ClosingBrace, bool ContainsUnexpandedParameterPack) : Expr(LambdaExprClass, T, VK_RValue, OK_Ordinary), IntroducerRange(IntroducerRange), CaptureDefaultLoc(CaptureDefaultLoc), - NumCaptures(Captures.size()), CaptureDefault(CaptureDefault), + NumCaptures(CaptureInits.size()), CaptureDefault(CaptureDefault), ExplicitParams(ExplicitParams), ExplicitResultType(ExplicitResultType), ClosingBrace(ClosingBrace) { - assert(CaptureInits.size() == Captures.size() && "Wrong number of arguments"); CXXRecordDecl *Class = getLambdaClass(); - CXXRecordDecl::LambdaDefinitionData &Data = Class->getLambdaData(); - - // FIXME: Propagate "has unexpanded parameter pack" bit. - - // Copy captures. - const ASTContext &Context = Class->getASTContext(); - Data.NumCaptures = NumCaptures; - Data.NumExplicitCaptures = 0; - Data.Captures = - (LambdaCapture *)Context.Allocate(sizeof(LambdaCapture) * NumCaptures); - LambdaCapture *ToCapture = Data.Captures; - for (unsigned I = 0, N = Captures.size(); I != N; ++I) { - if (Captures[I].isExplicit()) - ++Data.NumExplicitCaptures; - - *ToCapture++ = Captures[I]; - } + assert(NumCaptures == Class->capture_size() && "Wrong number of captures"); + assert(CaptureDefault == Class->getLambdaCaptureDefault()); // Copy initialization expressions for the non-static data members. Stmt **Stored = getStoredStmts(); @@ -1128,22 +1111,24 @@ LambdaExpr::LambdaExpr(QualType T, SourceRange IntroducerRange, setDependence(computeDependence(this, ContainsUnexpandedParameterPack)); } -LambdaExpr *LambdaExpr::Create( - const ASTContext &Context, CXXRecordDecl *Class, - SourceRange IntroducerRange, LambdaCaptureDefault CaptureDefault, - SourceLocation CaptureDefaultLoc, ArrayRef Captures, - bool ExplicitParams, bool ExplicitResultType, ArrayRef CaptureInits, - SourceLocation ClosingBrace, bool ContainsUnexpandedParameterPack) { +LambdaExpr *LambdaExpr::Create(const ASTContext &Context, CXXRecordDecl *Class, + SourceRange IntroducerRange, + LambdaCaptureDefault CaptureDefault, + SourceLocation CaptureDefaultLoc, + bool ExplicitParams, bool ExplicitResultType, + ArrayRef CaptureInits, + SourceLocation ClosingBrace, + bool ContainsUnexpandedParameterPack) { // Determine the type of the expression (i.e., the type of the // function object we're creating). QualType T = Context.getTypeDeclType(Class); - unsigned Size = totalSizeToAlloc(Captures.size() + 1); + unsigned Size = totalSizeToAlloc(CaptureInits.size() + 1); void *Mem = Context.Allocate(Size); return new (Mem) LambdaExpr(T, IntroducerRange, CaptureDefault, CaptureDefaultLoc, - Captures, ExplicitParams, ExplicitResultType, CaptureInits, - ClosingBrace, ContainsUnexpandedParameterPack); + ExplicitParams, ExplicitResultType, CaptureInits, ClosingBrace, + ContainsUnexpandedParameterPack); } LambdaExpr *LambdaExpr::CreateDeserialized(const ASTContext &C, diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp index b4336aa430eb6..e751a73957d0d 100644 --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -1782,6 +1782,8 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, CaptureInits.push_back(Init.get()); } + Class->setCaptures(Captures); + // C++11 [expr.prim.lambda]p6: // The closure type for a lambda-expression with no lambda-capture // has a public non-virtual non-explicit const conversion function @@ -1811,7 +1813,6 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, LambdaExpr *Lambda = LambdaExpr::Create(Context, Class, IntroducerRange, CaptureDefault, CaptureDefaultLoc, - Captures, ExplicitParams, ExplicitResultType, CaptureInits, EndLoc, ContainsUnexpandedParameterPack);