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
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits