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 Index: lib/Serialization/ASTReaderDecl.cpp =================================================================== --- lib/Serialization/ASTReaderDecl.cpp +++ lib/Serialization/ASTReaderDecl.cpp @@ -1761,8 +1761,6 @@ PFDI->second == ASTReader::PendingFakeDefinitionKind::Fake) { // We faked up this definition data because we found a class for which we'd // not yet loaded the definition. Replace it with the real thing now. - assert(!DD.hasLambdaData() && !MergeDD.hasLambdaData() && - "faked up lambda definition?"); PFDI->second = ASTReader::PendingFakeDefinitionKind::FakeLoaded; // Don't change which declaration is the definition; that is required @@ -1845,9 +1843,41 @@ // 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; + } + } + + // FIXME: Issue a diagnostic if ContextDecl doesn't match when we come to + // lazily load it. } if (D->getODRHash() != MergeDD.ODRHash) { 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(); + +#pragma clang module build PR38531 +module PR38531 {} +#pragma clang module contents +#pragma clang module begin PR38531 +template +struct S {}; +struct Fun { + template ())> + Fun(F) {} +}; +template +void foo(Fun=[]{}) {} +struct T { + void func() { + foo(); + } +}; +#pragma clang module end +#pragma clang module endbuild +#pragma clang module import PR38531 +S s;