diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -275,6 +275,10 @@ This fixes `Issue 55962 `_. - Printable Unicode characters within `static_assert` messages are no longer escaped. +- The ``-Winfinite-recursion`` diagnostic no longer warns about + unevaluated operands of a ``typeid`` expression, as they are now + modeled correctly in the CFG. This fixes + `Issue 21668 `_. Non-comprehensive list of changes in this release ------------------------------------------------- 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,25 @@ 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 the block to avoid + // CFG generation for unevaluated operands. + if (S && !S->isTypeDependent() && 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 @@ -171,3 +171,35 @@ } int wrapper_sum = test_wrapper<2>(); // expected-note{{instantiation}} + +namespace std { +class type_info { +public: + virtual ~type_info(); + const char *name() const { return __name; } + bool operator==(const type_info &__arg) const { + return __name == __arg.__name; + } + + bool operator!=(const type_info &__arg) const { + return !operator==(__arg); + } + +protected: + const char *__name; +}; +} // namespace std +struct Q { + virtual ~Q() = default; +}; + +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; +}