From 516e77b4bd80d0682f9166563524724cc171b5a1 Mon Sep 17 00:00:00 2001 From: Ted Kremenek Date: Thu, 6 Mar 2014 06:50:46 +0000 Subject: [PATCH] [-Wunreachable-code] don't warn about dead 'return ' dominated by a 'noreturn' call, where literal becomes an std::string. I have mixed feelings about this one. It's used all over the codebase, and is analogous to the current heuristic for ordinary C string literals. This requires some ad hoc pattern matching of the AST. While the test case mirrors what we see std::string in libc++, it's not really testing the libc++ headers. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@203091 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Analysis/ReachableCode.cpp | 54 +++++++++++++++++++++++++++++-- test/SemaCXX/warn-unreachable.cpp | 21 ++++++++++++ 2 files changed, 73 insertions(+), 2 deletions(-) diff --git a/lib/Analysis/ReachableCode.cpp b/lib/Analysis/ReachableCode.cpp index 8b192d2d61..79e8d8cb01 100644 --- a/lib/Analysis/ReachableCode.cpp +++ b/lib/Analysis/ReachableCode.cpp @@ -251,7 +251,10 @@ static bool bodyEndsWithNoReturn(const CFGBlock *B) { for (CFGBlock::const_reverse_iterator I = B->rbegin(), E = B->rend(); I != E; ++I) { if (Optional CS = I->getAs()) { - if (const CallExpr *CE = dyn_cast(CS->getStmt())) { + const Stmt *S = CS->getStmt(); + if (const ExprWithCleanups *EWC = dyn_cast(S)) + S = EWC->getSubExpr(); + if (const CallExpr *CE = dyn_cast(S)) { QualType CalleeType = CE->getCallee()->getType(); if (getFunctionExtInfo(*CalleeType).getNoReturn()) return true; @@ -290,6 +293,53 @@ static bool isEnumConstant(const Expr *Ex) { return isa(DR->getDecl()); } +static const Expr *stripStdStringCtor(const Expr *Ex) { + // Go crazy pattern matching an implicit construction of std::string(""). + const ExprWithCleanups *EWC = dyn_cast(Ex); + if (!EWC) + return 0; + const CXXConstructExpr *CCE = dyn_cast(EWC->getSubExpr()); + if (!CCE) + return 0; + QualType Ty = CCE->getType(); + if (const ElaboratedType *ET = dyn_cast(Ty)) + Ty = ET->getNamedType(); + const TypedefType *TT = dyn_cast(Ty); + StringRef Name = TT->getDecl()->getName(); + if (Name != "string") + return 0; + if (CCE->getNumArgs() != 1) + return 0; + const MaterializeTemporaryExpr *MTE = + dyn_cast(CCE->getArg(0)); + if (!MTE) + return 0; + CXXBindTemporaryExpr *CBT = + dyn_cast(MTE->GetTemporaryExpr()->IgnoreParenCasts()); + if (!CBT) + return 0; + Ex = CBT->getSubExpr()->IgnoreParenCasts(); + CCE = dyn_cast(Ex); + if (!CCE) + return 0; + if (CCE->getNumArgs() != 1) + return 0; + return dyn_cast(CCE->getArg(0)->IgnoreParenCasts()); +} + +/// Strip away "sugar" around trivial expressions that are for the +/// purpose of this analysis considered uninteresting for dead code warnings. +static const Expr *stripExprSugar(const Expr *Ex) { + Ex = Ex->IgnoreParenCasts(); + // If 'Ex' is a constructor for a std::string, strip that + // away. We can only get here if the trivial expression was + // something like a C string literal, with the std::string + // just wrapping that value. + if (const Expr *StdStringVal = stripStdStringCtor(Ex)) + return StdStringVal; + return Ex; +} + static bool isTrivialExpression(const Expr *Ex) { Ex = Ex->IgnoreParenCasts(); return isa(Ex) || isa(Ex) || @@ -324,7 +374,7 @@ static bool isTrivialReturnOrDoWhile(const CFGBlock *B, const Stmt *S) { if (Optional CS = I->getAs()) { if (const ReturnStmt *RS = dyn_cast(CS->getStmt())) { const Expr *RE = RS->getRetValue(); - if (RE && RE->IgnoreParenCasts() == Ex) + if (RE && stripExprSugar(RE->IgnoreParenCasts()) == Ex) return bodyEndsWithNoReturn(*B->pred_begin()); } break; diff --git a/test/SemaCXX/warn-unreachable.cpp b/test/SemaCXX/warn-unreachable.cpp index dbbcc8c50e..1fbe15c0f0 100644 --- a/test/SemaCXX/warn-unreachable.cpp +++ b/test/SemaCXX/warn-unreachable.cpp @@ -129,4 +129,25 @@ PR19040_test_return_t PR19040_fn1 () return PR19040_TEST_FAILURE; // expected-warning {{will never be executed}} } +__attribute__((noreturn)) +void raze(); + +namespace std { +template struct basic_string { + basic_string(const T* x) {} + ~basic_string() {}; +}; +typedef basic_string string; +} + +std::string testStr() { + raze(); + return ""; // no-warning +} + +std::string testStrWarn(const char *s) { + raze(); + return s; // expected-warning {{will never be executed}} +} + -- 2.40.0