From: Richard Smith Date: Wed, 2 May 2012 00:30:48 +0000 (+0000) Subject: Unrevert r155951, reverted in r155962, with two changes: X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c8c222830a1d8df8ed05bedfcac868fe6838fba8;p=clang Unrevert r155951, reverted in r155962, with two changes: * Work around build failures due to gcc 4.2 bugs. * Remove BodyIndexer::TraverseCXXOperatorCallExpr, which was not being called prior to this change, and whose presence disables a RecursiveASTVisitor stack space optimization after this change. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@155969 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index 93363b1715..8a6e85f226 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -405,18 +405,14 @@ private: bool TraverseFunctionHelper(FunctionDecl *D); bool TraverseVarHelper(VarDecl *D); - bool Walk(Stmt *S); - struct EnqueueJob { Stmt *S; Stmt::child_iterator StmtIt; - EnqueueJob(Stmt *S) : S(S), StmtIt() { - if (Expr *E = dyn_cast_or_null(S)) - S = E->IgnoreParens(); - } + EnqueueJob(Stmt *S) : S(S), StmtIt() {} }; bool dataTraverse(Stmt *S); + bool dataTraverseNode(Stmt *S, bool &EnqueueChildren); }; template @@ -435,7 +431,12 @@ bool RecursiveASTVisitor::dataTraverse(Stmt *S) { if (getDerived().shouldUseDataRecursionFor(CurrS)) { if (job.StmtIt == Stmt::child_iterator()) { - if (!Walk(CurrS)) return false; + bool EnqueueChildren = true; + if (!dataTraverseNode(CurrS, EnqueueChildren)) return false; + if (!EnqueueChildren) { + Queue.pop_back(); + continue; + } job.StmtIt = CurrS->child_begin(); } else { ++job.StmtIt; @@ -456,10 +457,18 @@ bool RecursiveASTVisitor::dataTraverse(Stmt *S) { } template -bool RecursiveASTVisitor::Walk(Stmt *S) { +bool RecursiveASTVisitor::dataTraverseNode(Stmt *S, + bool &EnqueueChildren) { + // Dispatch to the corresponding WalkUpFrom* function only if the derived + // class didn't override Traverse* (and thus the traversal is trivial). + // The cast here is necessary to work around a bug in old versions of g++. #define DISPATCH_WALK(NAME, CLASS, VAR) \ - return getDerived().WalkUpFrom##NAME(static_cast(VAR)); + if (&RecursiveASTVisitor::Traverse##NAME == \ + (bool (RecursiveASTVisitor::*)(CLASS*))&Derived::Traverse##NAME) \ + return getDerived().WalkUpFrom##NAME(static_cast(VAR)); \ + EnqueueChildren = false; \ + return getDerived().Traverse##NAME(static_cast(VAR)); if (BinaryOperator *BinOp = dyn_cast(S)) { switch (BinOp->getOpcode()) { diff --git a/tools/libclang/IndexBody.cpp b/tools/libclang/IndexBody.cpp index 239dde21bd..e975a6d1be 100644 --- a/tools/libclang/IndexBody.cpp +++ b/tools/libclang/IndexBody.cpp @@ -117,12 +117,6 @@ public: return true; } - bool TraverseCXXOperatorCallExpr(CXXOperatorCallExpr *E) { - if (E->getOperatorLoc().isInvalid()) - return true; // implicit. - return base::TraverseCXXOperatorCallExpr(E); - } - bool VisitDeclStmt(DeclStmt *S) { if (IndexCtx.shouldIndexFunctionLocalSymbols()) IndexCtx.indexDeclGroupRef(S->getDeclGroup()); diff --git a/unittests/Tooling/RecursiveASTVisitorTest.cpp b/unittests/Tooling/RecursiveASTVisitorTest.cpp index d4fda73ccb..953817e61f 100644 --- a/unittests/Tooling/RecursiveASTVisitorTest.cpp +++ b/unittests/Tooling/RecursiveASTVisitorTest.cpp @@ -165,6 +165,26 @@ public: } }; +class CXXOperatorCallExprTraverser + : public ExpectedLocationVisitor { +public: + // Use Traverse, not Visit, to check that data recursion optimization isn't + // bypassing the call of this function. + bool TraverseCXXOperatorCallExpr(CXXOperatorCallExpr *CE) { + Match(getOperatorSpelling(CE->getOperator()), CE->getExprLoc()); + return ExpectedLocationVisitor:: + TraverseCXXOperatorCallExpr(CE); + } +}; + +class ParenExprVisitor : public ExpectedLocationVisitor { +public: + bool VisitParenExpr(ParenExpr *Parens) { + Match("", Parens->getExprLoc()); + return true; + } +}; + TEST(RecursiveASTVisitor, VisitsBaseClassDeclarations) { TypeLocVisitor Visitor; Visitor.ExpectMatch("class X", 1, 30); @@ -345,4 +365,20 @@ TEST(RecursiveASTVisitor, NoRecursionInSelfFriend) { "vector_iterator it_int;\n")); } +TEST(RecursiveASTVisitor, TraversesOverloadedOperator) { + CXXOperatorCallExprTraverser Visitor; + Visitor.ExpectMatch("()", 4, 9); + EXPECT_TRUE(Visitor.runOver( + "struct A {\n" + " int operator()();\n" + "} a;\n" + "int k = a();\n")); +} + +TEST(RecursiveASTVisitor, VisitsParensDuringDataRecursion) { + ParenExprVisitor Visitor; + Visitor.ExpectMatch("", 1, 9); + EXPECT_TRUE(Visitor.runOver("int k = (4) + 9;\n")); +} + } // end namespace clang