diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp index 7fd24e2aa9ad2..e85feb779190f 100644 --- a/clang/lib/AST/ASTStructuralEquivalence.cpp +++ b/clang/lib/AST/ASTStructuralEquivalence.cpp @@ -1347,42 +1347,6 @@ IsStructurallyEquivalentLambdas(StructuralEquivalenceContext &Context, return true; } -/// Determine if context of a class is equivalent. -static bool IsRecordContextStructurallyEquivalent(RecordDecl *D1, - RecordDecl *D2) { - // The context should be completely equal, including anonymous and inline - // namespaces. - // We compare objects as part of full translation units, not subtrees of - // translation units. - DeclContext *DC1 = D1->getDeclContext()->getNonTransparentContext(); - DeclContext *DC2 = D2->getDeclContext()->getNonTransparentContext(); - while (true) { - // Special case: We allow a struct defined in a function to be equivalent - // with a similar struct defined outside of a function. - if ((DC1->isFunctionOrMethod() && DC2->isTranslationUnit()) || - (DC2->isFunctionOrMethod() && DC1->isTranslationUnit())) - return true; - - if (DC1->getDeclKind() != DC2->getDeclKind()) - return false; - if (DC1->isTranslationUnit()) - break; - if (DC1->isInlineNamespace() != DC2->isInlineNamespace()) - return false; - if (const auto *ND1 = dyn_cast(DC1)) { - const auto *ND2 = cast(DC2); - if (!DC1->isInlineNamespace() && - !IsStructurallyEquivalent(ND1->getIdentifier(), ND2->getIdentifier())) - return false; - } - - DC1 = DC1->getParent()->getNonTransparentContext(); - DC2 = DC2->getParent()->getNonTransparentContext(); - } - - return true; -} - /// Determine structural equivalence of two records. static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, RecordDecl *D1, RecordDecl *D2) { @@ -1422,12 +1386,6 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, } } - // If the records occur in different context (namespace), these should be - // different. This is specially important if the definition of one or both - // records is missing. - if (!IsRecordContextStructurallyEquivalent(D1, D2)) - return false; - // If both declarations are class template specializations, we know // the ODR applies, so check the template and template arguments. const auto *Spec1 = dyn_cast(D1); diff --git a/clang/unittests/AST/StructuralEquivalenceTest.cpp b/clang/unittests/AST/StructuralEquivalenceTest.cpp index 2f5b5c1460950..9ae0da8b9dd2c 100644 --- a/clang/unittests/AST/StructuralEquivalenceTest.cpp +++ b/clang/unittests/AST/StructuralEquivalenceTest.cpp @@ -929,136 +929,6 @@ TEST_F(StructuralEquivalenceTest, ExplicitBoolSame) { EXPECT_TRUE(testStructuralMatch(First, Second)); } -struct StructuralEquivalenceRecordContextTest : StructuralEquivalenceTest {}; - -TEST_F(StructuralEquivalenceRecordContextTest, NamespaceNoVsNamed) { - auto Decls = makeDecls("class X;", "namespace N { class X; }", - Lang_CXX03, cxxRecordDecl()); - EXPECT_FALSE(testStructuralMatch(Decls)); -} - -TEST_F(StructuralEquivalenceRecordContextTest, NamespaceNamedVsNamed) { - auto Decls = makeDecls("namespace A { class X; }", - "namespace B { class X; }", Lang_CXX03, - cxxRecordDecl()); - EXPECT_FALSE(testStructuralMatch(Decls)); -} - -TEST_F(StructuralEquivalenceRecordContextTest, NamespaceAnonVsNamed) { - auto Decls = makeDecls("namespace { class X; }", - "namespace N { class X; }", Lang_CXX03, - cxxRecordDecl()); - EXPECT_FALSE(testStructuralMatch(Decls)); -} - -TEST_F(StructuralEquivalenceRecordContextTest, NamespaceNoVsAnon) { - auto Decls = makeDecls("class X;", "namespace { class X; }", - Lang_CXX03, cxxRecordDecl()); - EXPECT_FALSE(testStructuralMatch(Decls)); -} - -TEST_F(StructuralEquivalenceRecordContextTest, NamespaceAnonVsAnon) { - auto Decls = makeDecls("namespace { class X; }", - "namespace { class X; }", Lang_CXX03, - cxxRecordDecl()); - EXPECT_TRUE(testStructuralMatch(Decls)); -} - -TEST_F(StructuralEquivalenceRecordContextTest, NamespaceAnonVsAnonAnon) { - auto Decls = makeDecls("namespace { class X; }", - "namespace { namespace { class X; } }", - Lang_CXX03, cxxRecordDecl()); - EXPECT_FALSE(testStructuralMatch(Decls)); -} - -TEST_F(StructuralEquivalenceRecordContextTest, - NamespaceNamedNamedVsNamedNamed) { - auto Decls = makeDecls( - "namespace A { namespace N { class X; } }", - "namespace B { namespace N { class X; } }", Lang_CXX03, cxxRecordDecl()); - EXPECT_FALSE(testStructuralMatch(Decls)); -} - -TEST_F(StructuralEquivalenceRecordContextTest, NamespaceNamedVsInline) { - auto Decls = makeDecls( - "namespace A { namespace A { class X; } }", - "namespace A { inline namespace A { class X; } }", Lang_CXX17, - cxxRecordDecl()); - EXPECT_FALSE(testStructuralMatch(Decls)); -} - -TEST_F(StructuralEquivalenceRecordContextTest, NamespaceInlineVsInline) { - auto Decls = makeDecls( - "namespace A { inline namespace A { class X; } }", - "namespace A { inline namespace B { class X; } }", Lang_CXX17, - cxxRecordDecl()); - EXPECT_TRUE(testStructuralMatch(Decls)); -} - -TEST_F(StructuralEquivalenceRecordContextTest, NamespaceInlineTopLevel) { - auto Decls = makeDecls("inline namespace A { class X; } }", - "inline namespace B { class X; } }", - Lang_CXX17, cxxRecordDecl()); - EXPECT_TRUE(testStructuralMatch(Decls)); -} - -TEST_F(StructuralEquivalenceRecordContextTest, TransparentContext) { - auto Decls = makeDecls("extern \"C\" { class X; }", "class X;", - Lang_CXX03, cxxRecordDecl()); - EXPECT_TRUE(testStructuralMatch(Decls)); -} - -TEST_F(StructuralEquivalenceRecordContextTest, TransparentContextNE) { - auto Decls = makeDecls("extern \"C\" { class X; }", - "namespace { class X; }", Lang_CXX03, - cxxRecordDecl()); - EXPECT_FALSE(testStructuralMatch(Decls)); -} - -TEST_F(StructuralEquivalenceRecordContextTest, TransparentContextInNamespace) { - auto Decls = makeDecls( - "extern \"C\" { namespace N { class X; } }", - "namespace N { extern \"C\" { class X; } }", Lang_CXX03, cxxRecordDecl()); - EXPECT_TRUE(testStructuralMatch(Decls)); -} - -TEST_F(StructuralEquivalenceTest, NamespaceOfRecordMember) { - auto Decls = makeDecls( - R"( - class X; - class Y { X* x; }; - )", - R"( - namespace N { class X; } - class Y { N::X* x; }; - )", - Lang_CXX03, cxxRecordDecl(hasName("Y"))); - EXPECT_FALSE(testStructuralMatch(Decls)); -} - -TEST_F(StructuralEquivalenceTest, StructDefinitionInPrototype) { - auto Decls = makeDecls( - "struct Param { int a; }; void f(struct Param *p);", - "void f(struct Param { int a; } *p);", Lang_C89, - functionDecl(hasName("f"))); - EXPECT_TRUE(testStructuralMatch(Decls)); -} - -TEST_F(StructuralEquivalenceTest, StructDefinitionInPrototypeDifferentName) { - auto Decls = makeDecls( - "struct Param1 { int a; }; void f(struct Param1 *p);", - "void f(struct Param2 { int a; } *p);", Lang_C89, - functionDecl(hasName("f"))); - EXPECT_FALSE(testStructuralMatch(Decls)); -} - -TEST_F(StructuralEquivalenceRecordContextTest, RecordInsideFunction) { - auto Decls = makeDecls("struct Param { int a; };", - "void f() { struct Param { int a; }; }", - Lang_C89, recordDecl(hasName("Param"))); - EXPECT_TRUE(testStructuralMatch(Decls)); -} - struct StructuralEquivalenceEnumTest : StructuralEquivalenceTest {}; TEST_F(StructuralEquivalenceEnumTest, FwdDeclEnumShouldBeEqualWithFwdDeclEnum) {