alexfh created this revision. alexfh added reviewers: sbenza, bkramer. alexfh added a subscriber: cfe-commits.
This patch fixes an assertion failure on some matchers containing templateArgument() on some code in some configurations. I couldn't come up with a consistent repro, since the failure depens on the order of elements in a map. http://reviews.llvm.org/D18136 contains a matcher that causes the issue at least on some configurations. The fix turned out to require non-trivial amount of code, very similar to TemplateArgument::structurallyEquals. I'd prefer to use TemplateArgument::Profile, if it was possible without ASTContext. Another alternative would be to add operator< for TemplateArgument, but since it's only needed in DynTypedNode, I decided to make this code private to DynTypedNode. http://reviews.llvm.org/D19144 Files: include/clang/AST/ASTTypeTraits.h lib/AST/ASTTypeTraits.cpp unittests/AST/ASTTypeTraitsTest.cpp
Index: unittests/AST/ASTTypeTraitsTest.cpp =================================================================== --- unittests/AST/ASTTypeTraitsTest.cpp +++ unittests/AST/ASTTypeTraitsTest.cpp @@ -180,5 +180,65 @@ EXPECT_FALSE(Node < Node); } +TEST(DynTypedNode, TemplateArgumentNull) { + TemplateArgument T; + DynTypedNode Node = DynTypedNode::create(T); + EXPECT_TRUE(Node == Node); + EXPECT_FALSE(Node < Node); +} + +TEST(DynTypedNode, TemplateArgumentQualType) { + QualType QT; + TemplateArgument T(QT); + DynTypedNode Node = DynTypedNode::create(T); + EXPECT_TRUE(Node == Node); + EXPECT_FALSE(Node < Node); +} + +TEST(DynTypedNode, TemplateArgumentNullPtr) { + QualType QT; + TemplateArgument T(QT, true); + DynTypedNode Node = DynTypedNode::create(T); + EXPECT_TRUE(Node == Node); + EXPECT_FALSE(Node < Node); +} + +TEST(DynTypedNode, TemplateArgumentExpr) { + BuiltinType Void(BuiltinType::Void); + QualType QT(&Void, 0); + NoInitExpr E(QT); + TemplateArgument T(&E); + DynTypedNode Node = DynTypedNode::create(T); + EXPECT_TRUE(Node == Node); + EXPECT_FALSE(Node < Node); +} + +TEST(DynTypedNode, TemplateArgumentTemplate) { + TemplateName TN; + TemplateArgument T(TN); + DynTypedNode Node = DynTypedNode::create(T); + EXPECT_TRUE(Node == Node); + EXPECT_FALSE(Node < Node); +} + +TEST(DynTypedNode, TemplateArgumentTemplateExpansion) { + TemplateName TN; + TemplateArgument T(TN, llvm::Optional<unsigned>(0u)); + DynTypedNode Node = DynTypedNode::create(T); + EXPECT_TRUE(Node == Node); + EXPECT_FALSE(Node < Node); +} + +TEST(DynTypedNode, TemplateArgumentPack) { + TemplateArgument TP[1]; + TemplateArgument T(TP); + DynTypedNode Node = DynTypedNode::create(T); + EXPECT_TRUE(Node == Node); + EXPECT_FALSE(Node < Node); +} + +// FIXME: Figure out how to test TemplateArgument of the Declaration and +// Integral kinds. + } // namespace ast_type_traits } // namespace clang Index: lib/AST/ASTTypeTraits.cpp =================================================================== --- lib/AST/ASTTypeTraits.cpp +++ lib/AST/ASTTypeTraits.cpp @@ -150,5 +150,54 @@ return SourceRange(); } +bool DynTypedNode::TemplateArgumentLess(const TemplateArgument &LHS, + const TemplateArgument &RHS) { + if (LHS.getKind() != RHS.getKind()) return LHS.getKind() < RHS.getKind(); + + switch (LHS.getKind()) { + case TemplateArgument::Null: + return false; + + case TemplateArgument::Type: + return LHS.getAsType().getAsOpaquePtr() < + RHS.getAsType().getAsOpaquePtr(); + + case TemplateArgument::Expression: + return LHS.getAsExpr() < RHS.getAsExpr(); + + case TemplateArgument::Template: + case TemplateArgument::TemplateExpansion: + return LHS.getAsTemplateOrTemplatePattern().getAsVoidPointer() < + RHS.getAsTemplateOrTemplatePattern().getAsVoidPointer(); + + case TemplateArgument::NullPtr: + return LHS.getNullPtrType().getAsOpaquePtr() < + RHS.getNullPtrType().getAsOpaquePtr(); + + case TemplateArgument::Pack: { + if (LHS.pack_size() != RHS.pack_size()) + return LHS.pack_size() < RHS.pack_size(); + auto PackA = LHS.getPackAsArray(); + auto PackB = RHS.getPackAsArray(); + for (unsigned I = 0, E = PackA.size(); I != E; ++I) + if (!PackA[I].structurallyEquals(PackB[I])) + return TemplateArgumentLess(PackA[I], PackB[I]); + return false; + } + + case TemplateArgument::Declaration: + return (LHS.getAsDecl() ? LHS.getAsDecl()->getCanonicalDecl() : nullptr) < + (RHS.getAsDecl() ? RHS.getAsDecl()->getCanonicalDecl() : nullptr); + + case TemplateArgument::Integral: + return std::make_pair(LHS.getIntegralType().getAsOpaquePtr(), + LHS.getAsIntegral()) < + std::make_pair(RHS.getIntegralType().getAsOpaquePtr(), + RHS.getAsIntegral()); + + } + llvm_unreachable("Unsupported or invalid TemplateArgument kind"); +} + } // end namespace ast_type_traits } // end namespace clang Index: include/clang/AST/ASTTypeTraits.h =================================================================== --- include/clang/AST/ASTTypeTraits.h +++ include/clang/AST/ASTTypeTraits.h @@ -296,6 +296,10 @@ NNSLB.getOpaqueData()); } + if (ASTNodeKind::getFromNodeKind<TemplateArgument>().isSame(NodeKind)) + return TemplateArgumentLess(getUnchecked<TemplateArgument>(), + Other.getUnchecked<TemplateArgument>()); + assert(getMemoizationData() && Other.getMemoizationData()); return getMemoizationData() < Other.getMemoizationData(); } @@ -316,6 +320,10 @@ return getUnchecked<NestedNameSpecifierLoc>() == Other.getUnchecked<NestedNameSpecifierLoc>(); + if (ASTNodeKind::getFromNodeKind<TemplateArgument>().isSame(NodeKind)) + return getUnchecked<TemplateArgument>().structurallyEquals( + Other.getUnchecked<TemplateArgument>()); + assert(getMemoizationData() && Other.getMemoizationData()); return getMemoizationData() == Other.getMemoizationData(); } @@ -428,6 +436,9 @@ } }; + static bool TemplateArgumentLess(const TemplateArgument &LHS, + const TemplateArgument &RHS); + ASTNodeKind NodeKind; /// \brief Stores the data of the node.
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits