diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp --- a/clang/lib/AST/ASTStructuralEquivalence.cpp +++ b/clang/lib/AST/ASTStructuralEquivalence.cpp @@ -1095,6 +1095,17 @@ D2->getLambdaCallOperator())) return false; + auto &SM1 = Context.FromCtx.getSourceManager(); + auto &SM2 = Context.ToCtx.getSourceManager(); + auto Loc1 = SM1.getSpellingLoc(SM1.getExpansionLoc(D1->getLocation())); + auto Loc2 = SM2.getSpellingLoc(SM2.getExpansionLoc(D2->getLocation())); + if (SM1.getSpellingLineNumber(Loc1) != SM2.getSpellingLineNumber(Loc2)) + return false; + if (SM1.getSpellingColumnNumber(Loc1) != SM2.getSpellingColumnNumber(Loc2)) + return false; + if (SM1.getFilename(Loc1) != SM2.getFilename(Loc2)) + return false; + return true; } diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp --- a/clang/unittests/AST/ASTImporterTest.cpp +++ b/clang/unittests/AST/ASTImporterTest.cpp @@ -5083,6 +5083,70 @@ INSTANTIATE_TEST_CASE_P(ParameterizedTests, CanonicalRedeclChain, ::testing::Values(ArgVector()), ); +TEST_P(ASTImporterOptionSpecificTestBase, LambdasAreDifferentiated) { + Decl *FromTU = getTuDecl( + R"( + void f() { + auto L0 = [](){}; + auto L1 = [](){}; + } + )", + Lang_CXX11, "input0.cc"); + auto Pattern = lambdaExpr(); + CXXRecordDecl *FromL0 = + FirstDeclMatcher().match(FromTU, Pattern)->getLambdaClass(); + CXXRecordDecl *FromL1 = + LastDeclMatcher().match(FromTU, Pattern)->getLambdaClass(); + ASSERT_NE(FromL0, FromL1); + + CXXRecordDecl *ToL0 = Import(FromL0, Lang_CXX11); + CXXRecordDecl *ToL1 = Import(FromL1, Lang_CXX11); + EXPECT_NE(ToL0, ToL1); +} + +TEST_P(ASTImporterOptionSpecificTestBase, + LambdasInFunctionParamsAreDifferentiated) { + Decl *FromTU = getTuDecl( + R"( + template + void f(F0 L0 = [](){}, F1 L1 = [](){}) {} + )", + Lang_CXX11, "input0.cc"); + auto Pattern = cxxRecordDecl(isLambda()); + CXXRecordDecl *FromL0 = + FirstDeclMatcher().match(FromTU, Pattern); + CXXRecordDecl *FromL1 = + LastDeclMatcher().match(FromTU, Pattern); + ASSERT_NE(FromL0, FromL1); + + CXXRecordDecl *ToL0 = Import(FromL0, Lang_CXX11); + CXXRecordDecl *ToL1 = Import(FromL1, Lang_CXX11); + ASSERT_NE(ToL0, ToL1); +} + +TEST_P(ASTImporterOptionSpecificTestBase, + LambdasInFunctionParamsAreDifferentiatedWhenMacroIsUsed) { + Decl *FromTU = getTuDecl( + R"( + #define LAMBDA [](){} + template + void f(F0 L0 = LAMBDA, F1 L1 = LAMBDA) {} + )", + Lang_CXX11, "input0.cc"); + auto Pattern = cxxRecordDecl(isLambda()); + CXXRecordDecl *FromL0 = + FirstDeclMatcher().match(FromTU, Pattern); + CXXRecordDecl *FromL1 = + LastDeclMatcher().match(FromTU, Pattern); + ASSERT_NE(FromL0, FromL1); + + Import(FromL0, Lang_CXX11); + Import(FromL1, Lang_CXX11); + CXXRecordDecl *ToL0 = Import(FromL0, Lang_CXX11); + CXXRecordDecl *ToL1 = Import(FromL1, Lang_CXX11); + ASSERT_NE(ToL0, ToL1); +} + INSTANTIATE_TEST_CASE_P(ParameterizedTests, ASTImporterLookupTableTest, DefaultTestValuesForRunOptions, ); diff --git a/clang/unittests/AST/StructuralEquivalenceTest.cpp b/clang/unittests/AST/StructuralEquivalenceTest.cpp --- a/clang/unittests/AST/StructuralEquivalenceTest.cpp +++ b/clang/unittests/AST/StructuralEquivalenceTest.cpp @@ -849,6 +849,33 @@ EXPECT_TRUE(testStructuralMatch(L0, L1)); } +TEST_F(StructuralEquivalenceLambdaTest, + LambdaClassesWithDifferentSpellingLocations) { + auto t = makeDecls("void f() { auto L = [](int){}; }", + "void f() { auto L = [](int){}; }", + Lang_CXX11, lambdaExpr(), lambdaExpr()); + CXXRecordDecl *L0 = get<0>(t)->getLambdaClass(); + CXXRecordDecl *L1 = get<1>(t)->getLambdaClass(); + EXPECT_FALSE(testStructuralMatch(L0, L1)); +} + +TEST_F(StructuralEquivalenceLambdaTest, + LambdaClassesWithDifferentExpansionLocations) { + auto t = makeDecls( + R"( + #define LAMBDA [](){} + void f() { auto L = LAMBDA; } + )", + R"( + #define LAMBDA [](){} + void f() { auto L = LAMBDA; } + )", + Lang_CXX11, lambdaExpr(), lambdaExpr()); + CXXRecordDecl *L0 = get<0>(t)->getLambdaClass(); + CXXRecordDecl *L1 = get<1>(t)->getLambdaClass(); + EXPECT_FALSE(testStructuralMatch(L0, L1)); +} + TEST_F(StructuralEquivalenceTest, CompareSameDeclWithMultiple) { auto t = makeNamedDecls( "struct A{ }; struct B{ }; void foo(A a, A b);",