summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/AST/DeclCXX.h7
-rw-r--r--clang/lib/AST/DeclCXX.cpp6
-rw-r--r--clang/lib/Serialization/ASTReaderDecl.cpp2
-rw-r--r--clang/lib/Serialization/ASTWriter.cpp2
-rw-r--r--clang/test/Modules/lambda-context.cpp22
-rw-r--r--clang/test/PCH/cxx11-lambdas.mm7
6 files changed, 39 insertions, 7 deletions
diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h
index 2071c1b0e1d..f2b798b5a35 100644
--- a/clang/include/clang/AST/DeclCXX.h
+++ b/clang/include/clang/AST/DeclCXX.h
@@ -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.
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 7395db586be..5256eda24bd 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -1107,6 +1107,12 @@ CXXRecordDecl::getGenericLambdaTemplateParameterList() const {
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())
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index 04231cd8e0b..e00c9561cd8 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -1539,7 +1539,7 @@ void ASTDeclReader::ReadCXXDefinitionData(
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;
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index 72b2bf6d168..7f9ae8df1cd 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -5565,7 +5565,7 @@ void ASTRecordWriter::AddCXXDefinitionData(const CXXRecordDecl *D) {
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];
diff --git a/clang/test/Modules/lambda-context.cpp b/clang/test/Modules/lambda-context.cpp
new file mode 100644
index 00000000000..6ce482c2b76
--- /dev/null
+++ b/clang/test/Modules/lambda-context.cpp
@@ -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
diff --git a/clang/test/PCH/cxx11-lambdas.mm b/clang/test/PCH/cxx11-lambdas.mm
index 5d3323a02cf..1f568f05e11 100644
--- a/clang/test/PCH/cxx11-lambdas.mm
+++ b/clang/test/PCH/cxx11-lambdas.mm
@@ -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
OpenPOWER on IntegriCloud