Skip to content

Commit

Permalink
[ASTImporter] Fix structural eq of lambdas
Browse files Browse the repository at this point in the history
Summary:
The structural equivalence check reported false eq between lambda classes
with different parameters in their call signature.
The solution is to check the methods for equality too in case of lambda
classes.

Reviewers: a_sidorin, a.sidorin

Subscribers: rnkovacs, dkrupp, Szelethus, gamesh411, cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D64075

llvm-svn: 366332
  • Loading branch information
Gabor Marton committed Jul 17, 2019
1 parent 80de11e commit ae512b8
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 0 deletions.
20 changes: 20 additions & 0 deletions clang/lib/AST/ASTStructuralEquivalence.cpp
Expand Up @@ -1085,6 +1085,19 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
return true;
}

/// Determine structural equivalence of two lambda classes.
static bool
IsStructurallyEquivalentLambdas(StructuralEquivalenceContext &Context,
CXXRecordDecl *D1, CXXRecordDecl *D2) {
assert(D1->isLambda() && D2->isLambda() &&
"Must be called on lambda classes");
if (!IsStructurallyEquivalent(Context, D1->getLambdaCallOperator(),
D2->getLambdaCallOperator()))
return false;

return true;
}

/// Determine structural equivalence of two records.
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
RecordDecl *D1, RecordDecl *D2) {
Expand Down Expand Up @@ -1166,6 +1179,13 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
D1CXX->getASTContext().getExternalSource()->CompleteType(D1CXX);
}

if (D1CXX->isLambda() != D2CXX->isLambda())
return false;
if (D1CXX->isLambda()) {
if (!IsStructurallyEquivalentLambdas(Context, D1CXX, D2CXX))
return false;
}

if (D1CXX->getNumBases() != D2CXX->getNumBases()) {
if (Context.Complain) {
Context.Diag2(D2->getLocation(),
Expand Down
16 changes: 16 additions & 0 deletions clang/unittests/AST/ASTImporterTest.cpp
Expand Up @@ -5122,6 +5122,22 @@ TEST_P(ASTImporterOptionSpecificTestBase, LambdaInFunctionParam) {
EXPECT_EQ(ToLSize, FromLSize);
}

TEST_P(ASTImporterOptionSpecificTestBase, LambdaInGlobalScope) {
Decl *FromTU = getTuDecl(
R"(
auto l1 = [](unsigned lp) { return 1; };
auto l2 = [](int lp) { return 2; };
int f(int p) {
return l1(p) + l2(p);
}
)",
Lang_CXX11, "input0.cc");
FunctionDecl *FromF = FirstDeclMatcher<FunctionDecl>().match(
FromTU, functionDecl(hasName("f")));
FunctionDecl *ToF = Import(FromF, Lang_CXX11);
EXPECT_TRUE(ToF);
}

struct LLDBLookupTest : ASTImporterOptionSpecificTestBase {
LLDBLookupTest() {
Creator = [](ASTContext &ToContext, FileManager &ToFileManager,
Expand Down
52 changes: 52 additions & 0 deletions clang/unittests/AST/StructuralEquivalenceTest.cpp
Expand Up @@ -797,6 +797,58 @@ TEST_F(StructuralEquivalenceRecordTest, RecordsWithDifferentBody) {
EXPECT_FALSE(testStructuralMatch(t));
}

struct StructuralEquivalenceLambdaTest : StructuralEquivalenceTest {};

TEST_F(StructuralEquivalenceLambdaTest, LambdaClassesWithDifferentMethods) {
// Get the LambdaExprs, unfortunately we can't match directly the underlying
// implicit CXXRecordDecl of the Lambda classes.
auto t = makeDecls<LambdaExpr>(
"void f() { auto L0 = [](int){}; }",
"void f() { auto L1 = [](){}; }",
Lang_CXX11,
lambdaExpr(),
lambdaExpr());
CXXRecordDecl *L0 = get<0>(t)->getLambdaClass();
CXXRecordDecl *L1 = get<1>(t)->getLambdaClass();
EXPECT_FALSE(testStructuralMatch(L0, L1));
}

TEST_F(StructuralEquivalenceLambdaTest, LambdaClassesWithEqMethods) {
auto t = makeDecls<LambdaExpr>(
"void f() { auto L0 = [](int){}; }",
"void f() { auto L1 = [](int){}; }",
Lang_CXX11,
lambdaExpr(),
lambdaExpr());
CXXRecordDecl *L0 = get<0>(t)->getLambdaClass();
CXXRecordDecl *L1 = get<1>(t)->getLambdaClass();
EXPECT_TRUE(testStructuralMatch(L0, L1));
}

TEST_F(StructuralEquivalenceLambdaTest, LambdaClassesWithDifferentFields) {
auto t = makeDecls<LambdaExpr>(
"void f() { char* X; auto L0 = [X](){}; }",
"void f() { float X; auto L1 = [X](){}; }",
Lang_CXX11,
lambdaExpr(),
lambdaExpr());
CXXRecordDecl *L0 = get<0>(t)->getLambdaClass();
CXXRecordDecl *L1 = get<1>(t)->getLambdaClass();
EXPECT_FALSE(testStructuralMatch(L0, L1));
}

TEST_F(StructuralEquivalenceLambdaTest, LambdaClassesWithEqFields) {
auto t = makeDecls<LambdaExpr>(
"void f() { float X; auto L0 = [X](){}; }",
"void f() { float X; auto L1 = [X](){}; }",
Lang_CXX11,
lambdaExpr(),
lambdaExpr());
CXXRecordDecl *L0 = get<0>(t)->getLambdaClass();
CXXRecordDecl *L1 = get<1>(t)->getLambdaClass();
EXPECT_TRUE(testStructuralMatch(L0, L1));
}

TEST_F(StructuralEquivalenceTest, CompareSameDeclWithMultiple) {
auto t = makeNamedDecls(
"struct A{ }; struct B{ }; void foo(A a, A b);",
Expand Down

0 comments on commit ae512b8

Please sign in to comment.