Author: rsmith Date: Wed Aug 24 19:34:00 2016 New Revision: 279694 URL: http://llvm.org/viewvc/llvm-project?rev=279694&view=rev Log: Lazily load the ContextDecl for a lambda's DefinitionData, to fix a deserialization cycle caused by the ContextDecl recursively importing members of the lambda's closure type.
Added: cfe/trunk/test/Modules/lambda-context.cpp Modified: cfe/trunk/include/clang/AST/DeclCXX.h cfe/trunk/lib/AST/DeclCXX.cpp cfe/trunk/lib/Serialization/ASTReaderDecl.cpp cfe/trunk/lib/Serialization/ASTWriter.cpp cfe/trunk/test/PCH/cxx11-lambdas.mm Modified: cfe/trunk/include/clang/AST/DeclCXX.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=279694&r1=279693&r2=279694&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/DeclCXX.h (original) +++ cfe/trunk/include/clang/AST/DeclCXX.h Wed Aug 24 19:34:00 2016 @@ -571,7 +571,7 @@ class CXXRecordDecl : public RecordDecl /// actual DeclContext does not suffice. This is used for lambdas that /// occur within default arguments of function parameters within the class /// or within a data member initializer. - Decl *ContextDecl; + LazyDeclPtr ContextDecl; /// \brief The list of captures, both explicit and implicit, for this /// lambda. @@ -1673,10 +1673,7 @@ public: /// the declaration in which the lambda occurs, e.g., the function parameter /// or the non-static data member. Otherwise, it returns NULL to imply that /// the declaration context suffices. - Decl *getLambdaContextDecl() const { - assert(isLambda() && "Not a lambda closure type!"); - return getLambdaData().ContextDecl; - } + Decl *getLambdaContextDecl() const; /// \brief Set the mangling number and context declaration for a lambda /// class. Modified: cfe/trunk/lib/AST/DeclCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=279694&r1=279693&r2=279694&view=diff ============================================================================== --- cfe/trunk/lib/AST/DeclCXX.cpp (original) +++ cfe/trunk/lib/AST/DeclCXX.cpp Wed Aug 24 19:34:00 2016 @@ -1107,6 +1107,12 @@ CXXRecordDecl::getGenericLambdaTemplateP return nullptr; } +Decl *CXXRecordDecl::getLambdaContextDecl() const { + assert(isLambda() && "Not a lambda closure type!"); + ExternalASTSource *Source = getParentASTContext().getExternalSource(); + return getLambdaData().ContextDecl.get(Source); +} + static CanQualType GetConversionType(ASTContext &Context, NamedDecl *Conv) { QualType T = cast<CXXConversionDecl>(Conv->getUnderlyingDecl()->getAsFunction()) Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=279694&r1=279693&r2=279694&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original) +++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Wed Aug 24 19:34:00 2016 @@ -1539,7 +1539,7 @@ void ASTDeclReader::ReadCXXDefinitionDat Lambda.NumCaptures = Record[Idx++]; Lambda.NumExplicitCaptures = Record[Idx++]; Lambda.ManglingNumber = Record[Idx++]; - Lambda.ContextDecl = ReadDecl(Record, Idx); + Lambda.ContextDecl = ReadDeclID(Record, Idx); Lambda.Captures = (Capture*)Reader.Context.Allocate(sizeof(Capture)*Lambda.NumCaptures); Capture *ToCapture = Lambda.Captures; Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=279694&r1=279693&r2=279694&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTWriter.cpp (original) +++ cfe/trunk/lib/Serialization/ASTWriter.cpp Wed Aug 24 19:34:00 2016 @@ -5565,7 +5565,7 @@ void ASTRecordWriter::AddCXXDefinitionDa Record->push_back(Lambda.NumCaptures); Record->push_back(Lambda.NumExplicitCaptures); Record->push_back(Lambda.ManglingNumber); - AddDeclRef(Lambda.ContextDecl); + AddDeclRef(D->getLambdaContextDecl()); AddTypeSourceInfo(Lambda.MethodTyInfo); for (unsigned I = 0, N = Lambda.NumCaptures; I != N; ++I) { const LambdaCapture &Capture = Lambda.Captures[I]; Added: cfe/trunk/test/Modules/lambda-context.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/lambda-context.cpp?rev=279694&view=auto ============================================================================== --- cfe/trunk/test/Modules/lambda-context.cpp (added) +++ cfe/trunk/test/Modules/lambda-context.cpp Wed Aug 24 19:34:00 2016 @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -fmodules -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -fmodules -std=c++11 -include-pch %t %s -verify +// +// This test checks for a bug in the deserialization code that was only +// reachable with modules enabled, but actually building and using modules is +// not necessary in order to trigger it, so we just use PCH here to make the +// test simpler. + +#ifndef HEADER_INCLUDED +#define HEADER_INCLUDED + +struct X { template <typename T> X(T) {} }; +struct Y { Y(X x = [] {}); }; + +#else + +// This triggers us to load the specialization of X::X for Y's lambda. That +// lambda's context decl must not be loaded as a result of loading the lambda, +// as that would hit a deserialization cycle. +X x = [] {}; // expected-no-diagnostics + +#endif Modified: cfe/trunk/test/PCH/cxx11-lambdas.mm URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/cxx11-lambdas.mm?rev=279694&r1=279693&r2=279694&view=diff ============================================================================== --- cfe/trunk/test/PCH/cxx11-lambdas.mm (original) +++ cfe/trunk/test/PCH/cxx11-lambdas.mm Wed Aug 24 19:34:00 2016 @@ -38,6 +38,11 @@ int init_capture(T t) { return [&, x(t)] { return sizeof(x); }; } +struct X { + template <typename T> X(T); +}; +struct Y { Y(const X &x = [] {}); }; + #else // CHECK-PRINT: T add_slowly @@ -54,4 +59,6 @@ int add(int x, int y) { // CHECK-PRINT: init_capture // CHECK-PRINT: [&, x(t)] +X x = [] {}; + #endif _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits