Author: martong Date: Tue Jul 2 00:36:39 2019 New Revision: 364889 URL: http://llvm.org/viewvc/llvm-project?rev=364889&view=rev Log: [ASTImporter] Structural eq: handle DependentScopeDeclRefExpr
Summary: Structural equivalence did not handle dependent template args properly when the arg contained a DependentScopeDeclRefExpr. Reviewers: a_sidorin, a.sidorin Subscribers: rnkovacs, dkrupp, Szelethus, gamesh411, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D62329 Modified: cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp cfe/trunk/unittests/AST/StructuralEquivalenceTest.cpp Modified: cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp?rev=364889&r1=364888&r2=364889&view=diff ============================================================================== --- cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp (original) +++ cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp Tue Jul 2 00:36:39 2019 @@ -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(Str 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,26 @@ static bool IsStructurallyEquivalent(Str 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()); + } else if (auto CastE1 = dyn_cast<ImplicitCastExpr>(E1)) { + auto *CastE2 = dyn_cast<ImplicitCastExpr>(E2); + if (!CastE2) + return false; + if (!IsStructurallyEquivalent(Context, CastE1->getType(), + CastE2->getType())) + return false; + return IsStructurallyEquivalent(Context, CastE1->getSubExpr(), + CastE2->getSubExpr()); + } + // FIXME: Handle other kind of expressions! return true; } Modified: cfe/trunk/unittests/AST/StructuralEquivalenceTest.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/AST/StructuralEquivalenceTest.cpp?rev=364889&r1=364888&r2=364889&view=diff ============================================================================== --- cfe/trunk/unittests/AST/StructuralEquivalenceTest.cpp (original) +++ cfe/trunk/unittests/AST/StructuralEquivalenceTest.cpp Tue Jul 2 00:36:39 2019 @@ -892,5 +892,143 @@ TEST_F(StructuralEquivalenceTemplateTest 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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits