elsteveogrande created this revision.
elsteveogrande added a reviewer: rsmith.
Herald added a subscriber: cfe-commits.

- Drop a couple of asserts preventing this (in the merge function)
- Merge all fields as usual
- Ensure select fields match, for ODR checking
- add previously-failing test to merge-lambdas.cpp

Test case by Andrew Gallagher

Test Plan: Andrew's repro from https://bugs.llvm.org/show_bug.cgi?id=38531 
broke before this change, works after.


Repository:
  rC Clang

https://reviews.llvm.org/D50949

Files:
  include/clang/AST/LambdaCapture.h
  lib/Serialization/ASTReaderDecl.cpp
  test/Modules/merge-lambdas.cpp

Index: test/Modules/merge-lambdas.cpp
===================================================================
--- test/Modules/merge-lambdas.cpp
+++ test/Modules/merge-lambdas.cpp
@@ -49,3 +49,25 @@
 
 #pragma clang module import A
 void (*p)() = f<int>();
+
+#pragma clang module build PR38531
+module PR38531 {}
+#pragma clang module contents
+#pragma clang module begin PR38531
+template <typename>
+struct S {};
+struct Fun {
+  template <typename F, typename T=decltype(S<F>())>
+  Fun(F) {}
+};
+template <typename>
+void foo(Fun=[]{}) {}
+struct T {
+  void func() {
+    foo<void>();
+  }
+};
+#pragma clang module end
+#pragma clang module endbuild
+#pragma clang module import PR38531
+S<void> s;
Index: lib/Serialization/ASTReaderDecl.cpp
===================================================================
--- lib/Serialization/ASTReaderDecl.cpp
+++ lib/Serialization/ASTReaderDecl.cpp
@@ -1763,12 +1763,6 @@
 
     Reader.PendingFakeDefinitionData.erase(PFDI);
 
-    // FIXME: handle serialized lambdas
-    assert(!(DD.hasLambdaData() || MergeDD.hasLambdaData()) &&
-           "faked up lambda definition?");
-
-    assert(DD.hasLambdaData() == MergeDD.hasLambdaData());
-
     // Don't change which declaration is the definition; that is required
     // to be invariant once we select it.
     auto *Def = DD.Definition;
@@ -1849,9 +1843,44 @@
   // FIXME: Issue a diagnostic if FirstFriend doesn't match when we come to
   // lazily load it.
 
-  if (DD.hasLambdaData()) {
-    // FIXME: ODR-checking for merging lambdas (this happens, for instance,
-    // when they occur within the body of a function template specialization).
+  assert (DD.hasLambdaData() == MergeDD.hasLambdaData() &&
+          "Merging definitions, one of which is a lambda, the other not?");
+  if (DD.hasLambdaData() && MergeDD.hasLambdaData()) {
+    auto &LDD = *DD.LambdaData;
+    auto &MergeLDD = *MergeDD.LambdaData;
+
+#define MATCH_LAM_FIELD(Field) \
+                            DetectedOdrViolation |= LDD.Field != MergeLDD.Field;
+    MATCH_LAM_FIELD(Dependent)
+    MATCH_LAM_FIELD(IsGenericLambda)
+    MATCH_LAM_FIELD(CaptureDefault)
+    MATCH_LAM_FIELD(NumCaptures)
+    MATCH_LAM_FIELD(NumExplicitCaptures)
+    MATCH_LAM_FIELD(ManglingNumber)
+#undef MATCH_LAM_FIELD
+
+    auto *C1 = LDD.Captures;
+    auto *C2 = MergeLDD.Captures;
+    for (int I = 0; !DetectedOdrViolation && I < LDD.NumCaptures; ++I) {
+      if (C1[I] != C2[I]) {
+        DetectedOdrViolation = true;
+      }
+    }
+
+    if (LDD.MethodTyInfo || MergeLDD.MethodTyInfo) {
+      if (!LDD.MethodTyInfo ||
+          !MergeLDD.MethodTyInfo ||
+          (LDD.MethodTyInfo->getType().getTypePtrOrNull() !=
+              MergeLDD.MethodTyInfo->getType().getTypePtrOrNull())) {
+        DetectedOdrViolation = true;
+        llvm::errs() << "@@@ T1 " << LDD.MethodTyInfo->getType().getTypePtrOrNull()
+                   << " T2 " << MergeLDD.MethodTyInfo->getType().getTypePtrOrNull()
+                   << '\n';
+      }
+    }
+
+    // FIXME: Issue a diagnostic if ContextDecl doesn't match when we come to
+    // lazily load it.
   }
 
   if (D->getODRHash() != MergeDD.ODRHash) {
Index: include/clang/AST/LambdaCapture.h
===================================================================
--- include/clang/AST/LambdaCapture.h
+++ include/clang/AST/LambdaCapture.h
@@ -135,6 +135,16 @@
     assert(isPackExpansion() && "No ellipsis location for a non-expansion");
     return EllipsisLoc;
   }
+
+  // [In]Equality operators -- primarily for ODR-compliance checking.
+
+  bool operator==(LambdaCapture const &RHS) const {
+    return DeclAndBits == RHS.DeclAndBits;
+  }
+
+  bool operator!=(LambdaCapture const &RHS) const {
+    return !operator==(RHS);
+  }
 };
 
 } // end namespace clang
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to