diff options
-rw-r--r-- | compilerplugins/clang/redundantcast.cxx | 27 | ||||
-rw-r--r-- | compilerplugins/clang/test/redundantcast.cxx | 2 | ||||
-rw-r--r-- | include/o3tl/temporary.hxx | 2 |
3 files changed, 30 insertions, 1 deletions
diff --git a/compilerplugins/clang/redundantcast.cxx b/compilerplugins/clang/redundantcast.cxx index 088349fa1d9c..27566809494c 100644 --- a/compilerplugins/clang/redundantcast.cxx +++ b/compilerplugins/clang/redundantcast.cxx @@ -109,6 +109,14 @@ public: expr->isSemanticForm() ? expr : expr->getSemanticForm(), queue); } + bool TraverseReturnStmt(ReturnStmt * stmt) { + auto const saved = returnExpr_; + returnExpr_ = stmt->getRetValue(); + auto const ret = FilteringRewritePlugin::TraverseReturnStmt(stmt); + returnExpr_ = saved; + return ret; + } + bool VisitImplicitCastExpr(ImplicitCastExpr const * expr); bool VisitCXXStaticCastExpr(CXXStaticCastExpr const * expr); @@ -154,6 +162,8 @@ private: return compiler.getSourceManager().isMacroBodyExpansion(loc) && ignoreLocation(compiler.getSourceManager().getSpellingLoc(loc)); } + + Expr const * returnExpr_ = nullptr; }; bool RedundantCast::VisitImplicitCastExpr(const ImplicitCastExpr * expr) { @@ -502,6 +512,23 @@ bool RedundantCast::VisitCXXStaticCastExpr(CXXStaticCastExpr const * expr) { { return true; } + // For <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2266r1.html> "P2266R1: Simpler + // implicit move" (as implemented with <https://github.com/llvm/llvm-project/commit/ + // bf20631782183cd19e0bb7219e908c2bbb01a75f> "[clang] Implement P2266 Simpler implicit move" + // towards Clang 13), don't warn about a static_cast in a return statement like + // + // return static_cast<int &>(x); + // + // that needs an lvalue but where in a return statement like + // + // return x; + // + // the expression would now be an xvalue: + if (k3 == VK_LValue && k1 == VK_LValue && returnExpr_ != nullptr + && expr == returnExpr_->IgnoreParens()) + { + return true; + } // Don't warn if a static_cast on a pointer to function or member function is used to // disambiguate an overloaded function: if (fnptr) { diff --git a/compilerplugins/clang/test/redundantcast.cxx b/compilerplugins/clang/test/redundantcast.cxx index 97f4e6f73777..2a3721bb0c2e 100644 --- a/compilerplugins/clang/test/redundantcast.cxx +++ b/compilerplugins/clang/test/redundantcast.cxx @@ -286,6 +286,8 @@ void testStaticCast() { (void) static_cast<S const &&>(csr()); } +int & testReturnStaticCast(int && x) { return static_cast<int &>(x); } + void testFunctionalCast() { (void) int(nir()); // expected-error {{redundant functional cast from 'int' to 'int' [loplugin:redundantcast]}} (void) S(nsr()); diff --git a/include/o3tl/temporary.hxx b/include/o3tl/temporary.hxx index 7b6c9a1f9fc7..50d006e26d0e 100644 --- a/include/o3tl/temporary.hxx +++ b/include/o3tl/temporary.hxx @@ -18,7 +18,7 @@ namespace o3tl // and some call site doesn't need the value beyond the call itself (e.g., in a call like // std::modf(x, &o3tl::temporary(double())) to obtain the fractional part of x, ignoring the // integral part). -template <typename T> constexpr T& temporary(T&& x) { return x; } +template <typename T> constexpr T& temporary(T&& x) { return static_cast<T&>(x); } template <typename T> constexpr T& temporary(T&) = delete; } |