martong updated this revision to Diff 207063. martong marked 4 inline comments as done. martong added a comment.
- Add further checks for the DeclarationName overload Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D62329/new/ https://reviews.llvm.org/D62329 Files: clang/lib/AST/ASTStructuralEquivalence.cpp clang/unittests/AST/StructuralEquivalenceTest.cpp
Index: clang/unittests/AST/StructuralEquivalenceTest.cpp =================================================================== --- clang/unittests/AST/StructuralEquivalenceTest.cpp +++ clang/unittests/AST/StructuralEquivalenceTest.cpp @@ -892,5 +892,143 @@ EXPECT_FALSE(testStructuralMatch(First, Second)); } +struct StructuralEquivalenceDependentTemplateArgsTest + : StructuralEquivalenceTemplateTest {}; + +TEST_F(StructuralEquivalenceDependentTemplateArgsTest, + SameStructsInDependentArgs) { + std::string Code = + R"( + template <typename> + struct S1; + + template <typename> + struct enable_if; + + struct S + { + template <typename T, typename enable_if<S1<T>>::type> + void f(); + }; + )"; + auto t = makeDecls<FunctionTemplateDecl>(Code, Code, Lang_CXX11, + functionTemplateDecl(hasName("f"))); + EXPECT_TRUE(testStructuralMatch(t)); +} + +TEST_F(StructuralEquivalenceDependentTemplateArgsTest, + DifferentStructsInDependentArgs) { + std::string Code = + R"( + template <typename> + struct S1; + + template <typename> + struct S2; + + template <typename> + struct enable_if; + )"; + auto t = makeDecls<FunctionTemplateDecl>(Code + R"( + struct S + { + template <typename T, typename enable_if<S1<T>>::type> + void f(); + }; + )", + Code + R"( + struct S + { + template <typename T, typename enable_if<S2<T>>::type> + void f(); + }; + )", + Lang_CXX11, + functionTemplateDecl(hasName("f"))); + EXPECT_FALSE(testStructuralMatch(t)); +} + +TEST_F(StructuralEquivalenceDependentTemplateArgsTest, + SameStructsInDependentScopeDeclRefExpr) { + std::string Code = + R"( + template <typename> + struct S1; + + template <bool> + struct enable_if; + + struct S + { + template <typename T, typename enable_if<S1<T>::value>::type> + void f(); // DependentScopeDeclRefExpr:^^^^^^^^^^^^ + }; + )"; + auto t = makeDecls<FunctionTemplateDecl>(Code, Code, Lang_CXX11, + functionTemplateDecl(hasName("f"))); + EXPECT_TRUE(testStructuralMatch(t)); +} + +TEST_F(StructuralEquivalenceDependentTemplateArgsTest, + DifferentStructsInDependentScopeDeclRefExpr) { + std::string Code = + R"( + template <typename> + struct S1; + + template <typename> + struct S2; + + template <bool> + struct enable_if; + )"; + auto t = makeDecls<FunctionTemplateDecl>(Code + R"( + struct S + { + template <typename T, typename enable_if<S1<T>::value>::type> + void f(); // DependentScopeDeclRefExpr:^^^^^^^^^^^^ + }; + )", + Code + R"( + struct S + { + template <typename T, typename enable_if<S2<T>::value>::type> + void f(); + }; + )", + Lang_CXX, + functionTemplateDecl(hasName("f"))); + EXPECT_FALSE(testStructuralMatch(t)); +} + +TEST_F(StructuralEquivalenceDependentTemplateArgsTest, + DifferentValueInDependentScopeDeclRefExpr) { + std::string Code = + R"( + template <typename> + struct S1; + + template <bool> + struct enable_if; + )"; + auto t = makeDecls<FunctionTemplateDecl>(Code + R"( + struct S + { + template <typename T, typename enable_if<S1<T>::value1>::type> + void f(); // DependentScopeDeclRefExpr:^^^^^^^^^^^^ + }; + )", + Code + R"( + struct S + { + template <typename T, typename enable_if<S1<T>::value2>::type> + void f(); + }; + )", + Lang_CXX, + functionTemplateDecl(hasName("f"))); + EXPECT_FALSE(testStructuralMatch(t)); +} + } // end namespace ast_matchers } // end namespace clang Index: clang/lib/AST/ASTStructuralEquivalence.cpp =================================================================== --- clang/lib/AST/ASTStructuralEquivalence.cpp +++ clang/lib/AST/ASTStructuralEquivalence.cpp @@ -73,6 +73,7 @@ #include "clang/AST/DeclFriend.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/TemplateBase.h" #include "clang/AST/TemplateName.h" @@ -100,6 +101,59 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, const TemplateArgument &Arg1, const TemplateArgument &Arg2); +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + NestedNameSpecifier *NNS1, + NestedNameSpecifier *NNS2); +static bool IsStructurallyEquivalent(const IdentifierInfo *Name1, + const IdentifierInfo *Name2); + +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + const DeclarationName Name1, + const DeclarationName Name2) { + if (Name1.getNameKind() != Name2.getNameKind()) + return false; + + switch (Name1.getNameKind()) { + + case DeclarationName::Identifier: + return IsStructurallyEquivalent(Name1.getAsIdentifierInfo(), + Name2.getAsIdentifierInfo()); + + case DeclarationName::CXXConstructorName: + case DeclarationName::CXXDestructorName: + case DeclarationName::CXXConversionFunctionName: + return IsStructurallyEquivalent(Context, Name1.getCXXNameType(), + Name2.getCXXNameType()); + + case DeclarationName::CXXDeductionGuideName: { + if (!IsStructurallyEquivalent( + Context, Name1.getCXXDeductionGuideTemplate()->getDeclName(), + Name2.getCXXDeductionGuideTemplate()->getDeclName())) + return false; + return IsStructurallyEquivalent(Context, + Name1.getCXXDeductionGuideTemplate(), + Name2.getCXXDeductionGuideTemplate()); + } + + case DeclarationName::CXXOperatorName: + return Name1.getCXXOverloadedOperator() == Name2.getCXXOverloadedOperator(); + + case DeclarationName::CXXLiteralOperatorName: + return IsStructurallyEquivalent(Name1.getCXXLiteralIdentifier(), + Name2.getCXXLiteralIdentifier()); + + case DeclarationName::CXXUsingDirective: + return true; // FIXME When do we consider two using directives equal? + + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + return true; // FIXME + } + + llvm_unreachable("Unhandled kind of DeclarationName"); + return true; +} /// Determine structural equivalence of two expressions. static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, @@ -107,7 +161,17 @@ if (!E1 || !E2) return E1 == E2; - // FIXME: Actually perform a structural comparison! + if (auto *DE1 = dyn_cast<DependentScopeDeclRefExpr>(E1)) { + auto *DE2 = dyn_cast<DependentScopeDeclRefExpr>(E2); + if (!DE2) + return false; + if (!IsStructurallyEquivalent(Context, DE1->getDeclName(), + DE2->getDeclName())) + return false; + return IsStructurallyEquivalent(Context, DE1->getQualifier(), + DE2->getQualifier()); + } + // FIXME: Handle other kind of expressions! return true; }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits