diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp --- a/clang/lib/Analysis/CFG.cpp +++ b/clang/lib/Analysis/CFG.cpp @@ -564,6 +564,7 @@ AddStmtChoice asc); CFGBlock *VisitCXXThrowExpr(CXXThrowExpr *T); CFGBlock *VisitCXXTryStmt(CXXTryStmt *S); + CFGBlock *VisitCXXTypeidExpr(CXXTypeidExpr *S, AddStmtChoice asc); CFGBlock *VisitDeclStmt(DeclStmt *DS); CFGBlock *VisitDeclSubExpr(DeclStmt *DS); CFGBlock *VisitDefaultStmt(DefaultStmt *D); @@ -2220,6 +2221,9 @@ case Stmt::CXXTryStmtClass: return VisitCXXTryStmt(cast(S)); + case Stmt::CXXTypeidExprClass: + return VisitCXXTypeidExpr(cast(S), asc); + case Stmt::CXXForRangeStmtClass: return VisitCXXForRangeStmt(cast(S)); @@ -4045,6 +4049,28 @@ return VisitStmt(T, AddStmtChoice::AlwaysAdd); } +CFGBlock *CFGBuilder::VisitCXXTypeidExpr(CXXTypeidExpr *S, AddStmtChoice asc) { + if (asc.alwaysAdd(*this, S)) { + autoCreateBlock(); + appendStmt(Block, S); + } + + // C++ [expr.typeid]p3: + // When typeid is applied to an expression other than an glvalue of a + // polymorphic class type [...] [the] expression is an unevaluated + // operand. [...] + // We add only potentially evaluated statements to block to avoid + // CFG generation for unevaluated operands. + if (S && !S->isTypeDependent()) { + if (S->isPotentiallyEvaluated()) { + return VisitChildren(S); + } + } + + // Return block without CFG for unevaluated operands. + return Block; +} + CFGBlock *CFGBuilder::VisitDoStmt(DoStmt *D) { CFGBlock *LoopSuccessor = nullptr; diff --git a/clang/test/SemaCXX/warn-infinite-recursion.cpp b/clang/test/SemaCXX/warn-infinite-recursion.cpp --- a/clang/test/SemaCXX/warn-infinite-recursion.cpp +++ b/clang/test/SemaCXX/warn-infinite-recursion.cpp @@ -1,5 +1,7 @@ // RUN: %clang_cc1 %s -fsyntax-only -verify -Winfinite-recursion +#include + void a() { // expected-warning{{call itself}} a(); } @@ -171,3 +173,18 @@ } int wrapper_sum = test_wrapper<2>(); // expected-note{{instantiation}} + +struct Q { + virtual ~Q(){}; +}; + +Q q; +Q &evaluated_recursive_function(int x) { // expected-warning{{call itself}} + (void)typeid(evaluated_recursive_function(x)); // expected-warning {{expression with side effects will be evaluated despite being used as an operand to 'typeid'}} + return q; +} + +int unevaluated_recursive_function() { + (void)typeid(unevaluated_recursive_function()); + return 0; +} \ No newline at end of file