sammccall created this revision. sammccall added a reviewer: hokein. Herald added a project: clang. Herald added a subscriber: cfe-commits. sammccall requested review of this revision.
The following crashes on my system before this patch, but not after: void foo(int i) { switch (i) { case 1: case 2: ... 100000 cases ... ; } } clang-query -c="match stmt(hasAncestor(stmt()))" deep.c I'm not sure it's actually a sane testcase to run though, it's pretty slow :-) Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D88222 Files: clang/lib/AST/ParentMapContext.cpp
Index: clang/lib/AST/ParentMapContext.cpp =================================================================== --- clang/lib/AST/ParentMapContext.cpp +++ clang/lib/AST/ParentMapContext.cpp @@ -227,51 +227,57 @@ bool shouldVisitImplicitCode() const { return true; } + template <typename MapNodeTy, typename MapTy> + void MarkChild(MapNodeTy MapNode, MapTy *Parents) { + if (ParentStack.empty()) + return; + + // FIXME: Currently we add the same parent multiple times, but only + // when no memoization data is available for the type. + // For example when we visit all subexpressions of template + // instantiations; this is suboptimal, but benign: the only way to + // visit those is with hasAncestor / hasParent, and those do not create + // new matches. + // The plan is to enable DynTypedNode to be storable in a map or hash + // map. The main problem there is to implement hash functions / + // comparison operators for all types that DynTypedNode supports that + // do not have pointer identity. + auto &NodeOrVector = (*Parents)[MapNode]; + if (NodeOrVector.isNull()) { + if (const auto *D = ParentStack.back().get<Decl>()) + NodeOrVector = D; + else if (const auto *S = ParentStack.back().get<Stmt>()) + NodeOrVector = S; + else + NodeOrVector = new DynTypedNode(ParentStack.back()); + } else { + if (!NodeOrVector.template is<ParentVector *>()) { + auto *Vector = new ParentVector( + 1, getSingleDynTypedNodeFromParentMap(NodeOrVector)); + delete NodeOrVector.template dyn_cast<DynTypedNode *>(); + NodeOrVector = Vector; + } + + auto *Vector = NodeOrVector.template get<ParentVector *>(); + // Skip duplicates for types that have memoization data. + // We must check that the type has memoization data before calling + // std::find() because DynTypedNode::operator== can't compare all + // types. + bool Found = ParentStack.back().getMemoizationData() && + std::find(Vector->begin(), Vector->end(), + ParentStack.back()) != Vector->end(); + if (!Found) + Vector->push_back(ParentStack.back()); + } + } + template <typename T, typename MapNodeTy, typename BaseTraverseFn, typename MapTy> bool TraverseNode(T Node, MapNodeTy MapNode, BaseTraverseFn BaseTraverse, MapTy *Parents) { if (!Node) return true; - if (ParentStack.size() > 0) { - // FIXME: Currently we add the same parent multiple times, but only - // when no memoization data is available for the type. - // For example when we visit all subexpressions of template - // instantiations; this is suboptimal, but benign: the only way to - // visit those is with hasAncestor / hasParent, and those do not create - // new matches. - // The plan is to enable DynTypedNode to be storable in a map or hash - // map. The main problem there is to implement hash functions / - // comparison operators for all types that DynTypedNode supports that - // do not have pointer identity. - auto &NodeOrVector = (*Parents)[MapNode]; - if (NodeOrVector.isNull()) { - if (const auto *D = ParentStack.back().get<Decl>()) - NodeOrVector = D; - else if (const auto *S = ParentStack.back().get<Stmt>()) - NodeOrVector = S; - else - NodeOrVector = new DynTypedNode(ParentStack.back()); - } else { - if (!NodeOrVector.template is<ParentVector *>()) { - auto *Vector = new ParentVector( - 1, getSingleDynTypedNodeFromParentMap(NodeOrVector)); - delete NodeOrVector.template dyn_cast<DynTypedNode *>(); - NodeOrVector = Vector; - } - - auto *Vector = NodeOrVector.template get<ParentVector *>(); - // Skip duplicates for types that have memoization data. - // We must check that the type has memoization data before calling - // std::find() because DynTypedNode::operator== can't compare all - // types. - bool Found = ParentStack.back().getMemoizationData() && - std::find(Vector->begin(), Vector->end(), - ParentStack.back()) != Vector->end(); - if (!Found) - Vector->push_back(ParentStack.back()); - } - } + MarkChild(MapNode, Parents); ParentStack.push_back(createDynTypedNode(Node)); bool Result = BaseTraverse(); ParentStack.pop_back(); @@ -284,12 +290,6 @@ &Map.PointerParents); } - bool TraverseStmt(Stmt *StmtNode) { - return TraverseNode(StmtNode, StmtNode, - [&] { return VisitorBase::TraverseStmt(StmtNode); }, - &Map.PointerParents); - } - bool TraverseTypeLoc(TypeLoc TypeLocNode) { return TraverseNode( TypeLocNode, DynTypedNode::create(TypeLocNode), @@ -304,6 +304,17 @@ &Map.OtherParents); } + // Using generic TraverseNode for Stmt would prevent data-recursion. + bool dataTraverseStmtPre(Stmt *StmtNode) { + MarkChild(StmtNode, &Map.PointerParents); + ParentStack.push_back(createDynTypedNode(StmtNode)); + return true; + } + bool dataTraverseStmtPost(Stmt *StmtNode) { + ParentStack.pop_back(); + return true; + } + ParentMap ⤅ llvm::SmallVector<DynTypedNode, 16> ParentStack; };
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits