vsapsai created this revision.
vsapsai added reviewers: rsmith, bruno.
Herald added a subscriber: jkorous-apple.

During reading C++ definition data for lambda we can access
CXXRecordDecl representing lambda before we finished reading the
definition data. This can happen by reading a captured variable which is
VarDecl, then reading its decl context which is CXXMethodDecl `operator()`,
then trying to merge redeclarable methods and accessing
enclosing CXXRecordDecl. The call stack looks roughly like

  VisitCXXRecordDecl
    ReadCXXRecordDefinition
      VisitVarDecl
        VisitCXXMethodDecl
          mergeRedeclarable
            getPrimaryContextForMerging

If we add fake definition data at this point, later we'll hit the assertion

  Assertion failed: (!DD.IsLambda && !MergeDD.IsLambda && "faked up lambda 
definition?"), function MergeDefinitionData, file 
clang/lib/Serialization/ASTReaderDecl.cpp, line 1675.

The fix is to check if we are still reading real definition data and to
avoid adding a fake one in this case. Fixes PR32556.

rdar://problem/37461072


https://reviews.llvm.org/D43494

Files:
  clang/lib/Serialization/ASTReaderDecl.cpp
  clang/test/Modules/Inputs/self-referencing-lambda/a.h
  clang/test/Modules/Inputs/self-referencing-lambda/module.modulemap
  clang/test/Modules/self-referencing-lambda.cpp


Index: clang/test/Modules/self-referencing-lambda.cpp
===================================================================
--- /dev/null
+++ clang/test/Modules/self-referencing-lambda.cpp
@@ -0,0 +1,5 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I 
%S/Inputs/self-referencing-lambda %s -verify -emit-obj -o %t2.o
+// expected-no-diagnostics
+
+#include "a.h"
Index: clang/test/Modules/Inputs/self-referencing-lambda/module.modulemap
===================================================================
--- /dev/null
+++ clang/test/Modules/Inputs/self-referencing-lambda/module.modulemap
@@ -0,0 +1,4 @@
+module "a.h" {
+  header "a.h"
+  export *
+}
Index: clang/test/Modules/Inputs/self-referencing-lambda/a.h
===================================================================
--- /dev/null
+++ clang/test/Modules/Inputs/self-referencing-lambda/a.h
@@ -0,0 +1,4 @@
+void f() {
+  int x = 0;
+  auto q = [xm = x]{};
+}
Index: clang/lib/Serialization/ASTReaderDecl.cpp
===================================================================
--- clang/lib/Serialization/ASTReaderDecl.cpp
+++ clang/lib/Serialization/ASTReaderDecl.cpp
@@ -1782,7 +1782,10 @@
   else
     DD = new (C) struct CXXRecordDecl::DefinitionData(D);
 
+  assert(!D->IsBeingDefined && "Should not overwrite definition in progress");
+  D->IsBeingDefined = true;
   ReadCXXDefinitionData(*DD, D);
+  D->IsBeingDefined = false;
 
   // We might already have a definition for this record. This can happen either
   // because we're reading an update record, or because we've already done some
@@ -2963,6 +2966,9 @@
     if (!DD)
       DD = RD->getCanonicalDecl()->DefinitionData;
 
+    if (!DD && RD->isBeingDefined())
+      return nullptr;
+
     // If there's no definition yet, then DC's definition is added by an update
     // record, but we've not yet loaded that update record. In this case, we
     // commit to DC being the canonical definition now, and will fix this when


Index: clang/test/Modules/self-referencing-lambda.cpp
===================================================================
--- /dev/null
+++ clang/test/Modules/self-referencing-lambda.cpp
@@ -0,0 +1,5 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I %S/Inputs/self-referencing-lambda %s -verify -emit-obj -o %t2.o
+// expected-no-diagnostics
+
+#include "a.h"
Index: clang/test/Modules/Inputs/self-referencing-lambda/module.modulemap
===================================================================
--- /dev/null
+++ clang/test/Modules/Inputs/self-referencing-lambda/module.modulemap
@@ -0,0 +1,4 @@
+module "a.h" {
+  header "a.h"
+  export *
+}
Index: clang/test/Modules/Inputs/self-referencing-lambda/a.h
===================================================================
--- /dev/null
+++ clang/test/Modules/Inputs/self-referencing-lambda/a.h
@@ -0,0 +1,4 @@
+void f() {
+  int x = 0;
+  auto q = [xm = x]{};
+}
Index: clang/lib/Serialization/ASTReaderDecl.cpp
===================================================================
--- clang/lib/Serialization/ASTReaderDecl.cpp
+++ clang/lib/Serialization/ASTReaderDecl.cpp
@@ -1782,7 +1782,10 @@
   else
     DD = new (C) struct CXXRecordDecl::DefinitionData(D);
 
+  assert(!D->IsBeingDefined && "Should not overwrite definition in progress");
+  D->IsBeingDefined = true;
   ReadCXXDefinitionData(*DD, D);
+  D->IsBeingDefined = false;
 
   // We might already have a definition for this record. This can happen either
   // because we're reading an update record, or because we've already done some
@@ -2963,6 +2966,9 @@
     if (!DD)
       DD = RD->getCanonicalDecl()->DefinitionData;
 
+    if (!DD && RD->isBeingDefined())
+      return nullptr;
+
     // If there's no definition yet, then DC's definition is added by an update
     // record, but we've not yet loaded that update record. In this case, we
     // commit to DC being the canonical definition now, and will fix this when
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to