From 6e4a2540d4d8ad9e141b87ac3d2123d1c96366ef Mon Sep 17 00:00:00 2001 From: Noel Grandin Date: Thu, 29 Aug 2019 10:35:23 +0200 Subject: [PATCH] new loplugin:noexceptmove idea from mike kaganski look for places where we can mark move operators as noexcept, which makes some STL operations more efficient Change-Id: Id732b89d1fcadd5ceb0ea2b9d159fed06136330f Reviewed-on: https://gerrit.libreoffice.org/78251 Tested-by: Jenkins Reviewed-by: Noel Grandin --- compilerplugins/clang/noexceptmove.cxx | 319 ++++++++++++++++++++++ compilerplugins/clang/test/noexceptmove.cxx | 102 +++++++ connectivity/source/drivers/evoab2/NStatement.hxx | 2 +- cppu/source/uno/lbmap.cxx | 4 +- include/com/sun/star/uno/Reference.h | 4 +- include/com/sun/star/uno/Reference.hxx | 4 +- include/cppuhelper/weakref.hxx | 2 +- include/osl/pipe.hxx | 4 +- include/osl/pipe_decl.hxx | 4 +- include/osl/socket.hxx | 4 +- include/osl/socket_decl.hxx | 4 +- include/registry/registry.hxx | 2 +- include/rtl/byteseq.h | 4 +- include/rtl/byteseq.hxx | 4 +- include/rtl/ref.hxx | 2 +- include/rtl/string.hxx | 4 +- include/rtl/ustring.hxx | 4 +- include/sfx2/objsh.hxx | 4 +- include/store/store.hxx | 4 +- include/tools/globname.hxx | 4 +- include/tools/poly.hxx | 4 +- include/typelib/typedescription.hxx | 4 +- include/uno/dispatcher.hxx | 2 +- include/uno/environment.hxx | 2 +- include/uno/mapping.hxx | 4 +- include/unotools/itemholderbase.hxx | 2 +- include/unotools/tempfile.hxx | 2 +- include/vcl/alpha.hxx | 2 +- include/vcl/font.hxx | 4 +- include/vcl/region.hxx | 4 +- solenv/CompilerTest_compilerplugins_clang.mk | 1 + sw/inc/IDocumentMarkAccess.hxx | 4 +- sw/source/core/doc/docbm.cxx | 4 +- tools/source/generic/poly.cxx | 4 +- tools/source/ref/globname.cxx | 2 +- unotools/source/ucbhelper/tempfile.cxx | 2 +- vcl/source/font/font.cxx | 4 +- vcl/source/gdi/region.cxx | 4 +- 38 files changed, 481 insertions(+), 59 deletions(-) create mode 100644 compilerplugins/clang/noexceptmove.cxx create mode 100644 compilerplugins/clang/test/noexceptmove.cxx diff --git a/compilerplugins/clang/noexceptmove.cxx b/compilerplugins/clang/noexceptmove.cxx new file mode 100644 index 000000000000..483ccaed44cf --- /dev/null +++ b/compilerplugins/clang/noexceptmove.cxx @@ -0,0 +1,319 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +// versions before 9.0 didn't have getExceptionSpecType + +#include "plugin.hxx" + +// clang before V9 does not have API to report exception spec type +#if CLANG_VERSION >= 90000 + +#include "check.hxx" + +#include +#include + +/** + Look for move constructors that can be noexcept. +*/ + +namespace +{ +/// Look for the stuff that can be marked noexcept, but only if we also mark some of the callees noexcept. +/// Off by default so as not too annoy people. +constexpr bool bLookForStuffWeCanFix = false; + +class NoExceptMove : public loplugin::FilteringPlugin +{ +public: + explicit NoExceptMove(loplugin::InstantiationData const& data) + : FilteringPlugin(data) + { + } + + virtual void run() override + { + StringRef fn(handler.getMainFileName()); + // ONDXPagePtr::operator= calls ONDXPage::ReleaseRef which cannot be noexcept + if (loplugin::isSamePathname(fn, + SRCDIR "/connectivity/source/drivers/dbase/dindexnode.cxx")) + return; + TraverseDecl(compiler.getASTContext().getTranslationUnitDecl()); + } + + bool shouldVisitImplicitCode() const { return true; } + + bool TraverseCXXConstructorDecl(CXXConstructorDecl*); + bool TraverseCXXMethodDecl(CXXMethodDecl*); + bool VisitCallExpr(const CallExpr*); + bool VisitCXXConstructExpr(const CXXConstructExpr*); + bool VisitVarDecl(const VarDecl*); + +private: + llvm::Optional IsCallThrows(const CallExpr* callExpr); + std::vector m_ConstructorThrows; + std::vector> m_Exclusions; + std::vector m_CannotFix; +}; + +bool NoExceptMove::TraverseCXXConstructorDecl(CXXConstructorDecl* constructorDecl) +{ + const bool isMove = constructorDecl->isMoveConstructor() + && constructorDecl->getExceptionSpecType() == EST_None + && !constructorDecl->isDefaulted() && !constructorDecl->isDeleted() + && !ignoreLocation(constructorDecl) + && constructorDecl->isThisDeclarationADefinition(); + if (isMove) + { + m_ConstructorThrows.push_back(false); + m_Exclusions.emplace_back(); + m_CannotFix.push_back(false); + } + bool rv = RecursiveASTVisitor::TraverseCXXConstructorDecl(constructorDecl); + if (isMove) + { + if (!m_ConstructorThrows.back()) + { + report(DiagnosticsEngine::Warning, "move constructor can be noexcept", + constructorDecl->getSourceRange().getBegin()) + << constructorDecl->getSourceRange(); + auto canonicalDecl = constructorDecl->getCanonicalDecl(); + if (canonicalDecl != constructorDecl) + report(DiagnosticsEngine::Note, "declaration here", + canonicalDecl->getSourceRange().getBegin()) + << canonicalDecl->getSourceRange(); + } + else if (bLookForStuffWeCanFix && !m_CannotFix.back()) + { + report(DiagnosticsEngine::Warning, "move constructor can be noexcept", + constructorDecl->getSourceRange().getBegin()) + << constructorDecl->getSourceRange(); + auto canonicalDecl = constructorDecl->getCanonicalDecl(); + if (canonicalDecl != constructorDecl) + report(DiagnosticsEngine::Note, "declaration here", + canonicalDecl->getSourceRange().getBegin()) + << canonicalDecl->getSourceRange(); + for (const Decl* callDecl : m_Exclusions.back()) + report(DiagnosticsEngine::Warning, "but need to fix this to be noexcept", + callDecl->getSourceRange().getBegin()) + << callDecl->getSourceRange(); + } + m_ConstructorThrows.pop_back(); + m_Exclusions.pop_back(); + m_CannotFix.pop_back(); + } + return rv; +} + +bool NoExceptMove::TraverseCXXMethodDecl(CXXMethodDecl* methodDecl) +{ + bool isMove = methodDecl->isMoveAssignmentOperator() + && methodDecl->getExceptionSpecType() == EST_None && !methodDecl->isDefaulted() + && !methodDecl->isDeleted() && !ignoreLocation(methodDecl) + && methodDecl->isThisDeclarationADefinition(); + if (isMove) + { + StringRef fn = getFileNameOfSpellingLoc( + compiler.getSourceManager().getSpellingLoc(compat::getBeginLoc(methodDecl))); + // SfxObjectShellLock::operator= calls SotObject::OwnerLock whichs in turn calls stuff which cannot be noexcept + if (loplugin::isSamePathname(fn, SRCDIR "/include/sfx2/objsh.hxx")) + isMove = false; + } + if (isMove) + { + m_ConstructorThrows.push_back(false); + m_Exclusions.emplace_back(); + m_CannotFix.push_back(false); + } + bool rv = RecursiveASTVisitor::TraverseCXXMethodDecl(methodDecl); + if (isMove) + { + if (!m_ConstructorThrows.back()) + { + report(DiagnosticsEngine::Warning, "move operator= can be noexcept", + methodDecl->getSourceRange().getBegin()) + << methodDecl->getSourceRange(); + auto canonicalDecl = methodDecl->getCanonicalDecl(); + if (canonicalDecl != methodDecl) + report(DiagnosticsEngine::Note, "declaration here", + canonicalDecl->getSourceRange().getBegin()) + << canonicalDecl->getSourceRange(); + } + else if (bLookForStuffWeCanFix && !m_CannotFix.back()) + { + report(DiagnosticsEngine::Warning, "move operator= can be noexcept", + methodDecl->getSourceRange().getBegin()) + << methodDecl->getSourceRange(); + auto canonicalDecl = methodDecl->getCanonicalDecl(); + if (canonicalDecl != methodDecl) + report(DiagnosticsEngine::Note, "declaration here", + canonicalDecl->getSourceRange().getBegin()) + << canonicalDecl->getSourceRange(); + for (const Decl* callDecl : m_Exclusions.back()) + report(DiagnosticsEngine::Warning, "but need to fix this to be noexcept", + callDecl->getSourceRange().getBegin()) + << callDecl->getSourceRange(); + } + m_ConstructorThrows.pop_back(); + m_Exclusions.pop_back(); + m_CannotFix.pop_back(); + } + return rv; +} + +bool NoExceptMove::VisitCallExpr(const CallExpr* callExpr) +{ + if (ignoreLocation(callExpr)) + return true; + if (m_ConstructorThrows.empty()) + return true; + llvm::Optional bCallThrows = IsCallThrows(callExpr); + if (!bCallThrows) + { + callExpr->dump(); + if (callExpr->getCalleeDecl()) + callExpr->getCalleeDecl()->dump(); + report(DiagnosticsEngine::Warning, "whats up doc?", callExpr->getSourceRange().getBegin()) + << callExpr->getSourceRange(); + m_ConstructorThrows.back() = true; + return true; + } + if (*bCallThrows) + m_ConstructorThrows.back() = true; + return true; +} + +static bool IsCallThrowsSpec(clang::ExceptionSpecificationType est) +{ + return !(est == EST_DynamicNone || est == EST_NoThrow || est == EST_BasicNoexcept + || est == EST_NoexceptTrue); +} + +bool NoExceptMove::VisitCXXConstructExpr(const CXXConstructExpr* constructExpr) +{ + if (ignoreLocation(constructExpr)) + return true; + if (m_ConstructorThrows.empty()) + return true; + auto constructorDecl = constructExpr->getConstructor(); + auto est = constructorDecl->getExceptionSpecType(); + if (constructorDecl->isDefaulted() && est == EST_None) + ; // ok, non-throwing + else if (IsCallThrowsSpec(est)) + { + m_ConstructorThrows.back() = true; + } + return true; +} + +bool NoExceptMove::VisitVarDecl(const VarDecl* varDecl) +{ + if (varDecl->getLocation().isValid() && ignoreLocation(varDecl)) + return true; + if (m_ConstructorThrows.empty()) + return true; + // The clang AST does not show me implicit calls to destructors at the end of a block, + // so assume any local var decls of class type will call their destructor. + if (!varDecl->getType()->isRecordType()) + return true; + auto cxxRecordDecl = varDecl->getType()->getAsCXXRecordDecl(); + if (!cxxRecordDecl) + return true; + auto destructorDecl = cxxRecordDecl->getDestructor(); + if (!destructorDecl) + return true; + auto est = destructorDecl->getExceptionSpecType(); + if (destructorDecl->isDefaulted() && est == EST_None) + ; // ok, non-throwing + else if (IsCallThrowsSpec(est)) + { + m_ConstructorThrows.back() = true; + } + return true; +} + +llvm::Optional NoExceptMove::IsCallThrows(const CallExpr* callExpr) +{ + const FunctionDecl* calleeFunctionDecl = callExpr->getDirectCallee(); + if (calleeFunctionDecl) + { + auto est = calleeFunctionDecl->getExceptionSpecType(); + if (bLookForStuffWeCanFix) + { + if (est == EST_None && !ignoreLocation(calleeFunctionDecl)) + m_Exclusions.back().push_back(calleeFunctionDecl); + else + m_CannotFix.back() = true; + } + // Whitelist of functions that could be noexcept, but we can't change them because of backwards-compatibility reasons + // css::uno::XInterface::acquire + // css::uno::XInterface::release + if (calleeFunctionDecl->getIdentifier()) + { + auto name = calleeFunctionDecl->getName(); + if (auto cxxMethodDecl = dyn_cast(calleeFunctionDecl)) + if (loplugin::ContextCheck(cxxMethodDecl->getParent()->getDeclContext()) + .Namespace("uno") + .Namespace("star") + .Namespace("sun") + .Namespace("com") + .GlobalNamespace() + && (name == "acquire" || name == "release")) + return false; + if (name == "osl_releasePipe" || name == "osl_destroySocketAddr") + return false; + } + return IsCallThrowsSpec(est); + } + + auto calleeExpr = callExpr->getCallee(); + if (isa(calleeExpr) || isa(calleeExpr)) + { + m_CannotFix.back() = true; + return true; + } + + // check for call via function-pointer + clang::QualType calleeType; + if (auto fieldDecl = dyn_cast_or_null(callExpr->getCalleeDecl())) + calleeType = fieldDecl->getType(); + else if (auto varDecl = dyn_cast_or_null(callExpr->getCalleeDecl())) + calleeType = varDecl->getType(); + else + { + m_CannotFix.back() = true; + return llvm::Optional(); + } + + // whitelist of functions that could be noexcept, but we can't change them because of backwards-compatibility reasons + if (auto typedefType = calleeType->getAs()) + if (typedefType->getDecl()->getName() == "uno_ReleaseMappingFunc") + return false; + + if (calleeType->isPointerType()) + calleeType = calleeType->getPointeeType(); + auto funcProto = calleeType->getAs(); + if (!funcProto) + { + m_CannotFix.back() = true; + return llvm::Optional(); + } + + auto est = funcProto->getExceptionSpecType(); + if (bLookForStuffWeCanFix) + { + m_CannotFix.back() = true; // TODO, could improve + } + return IsCallThrowsSpec(est); +} + +loplugin::Plugin::Registration noexceptmove("noexceptmove"); +} + +#endif // CLANG_VERSION +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/compilerplugins/clang/test/noexceptmove.cxx b/compilerplugins/clang/test/noexceptmove.cxx new file mode 100644 index 000000000000..fda58deae403 --- /dev/null +++ b/compilerplugins/clang/test/noexceptmove.cxx @@ -0,0 +1,102 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#include "config_clang.h" + +// clang before V9 does not have API to report exception spec type +#if CLANG_VERSION >= 90000 + +namespace test1 +{ +class Mapping +{ + char* m_pMapping; + + // expected-error@+1 {{move constructor can be noexcept [loplugin:noexceptmove]}} + Mapping(Mapping&& other) + : m_pMapping(other.m_pMapping) + { + other.m_pMapping = nullptr; + } + + // expected-error@+1 {{move operator= can be noexcept [loplugin:noexceptmove]}} + Mapping& operator=(Mapping&& other) + { + m_pMapping = other.m_pMapping; + other.m_pMapping = nullptr; + return *this; + } +}; +}; + +// No warning expected, because calling throwing function. +namespace test2 +{ +void foo() noexcept(false); + +class Bar +{ + Bar(Bar&&) { foo(); } +}; +}; + +// no warning expected, because calling throwing constructor +namespace test3 +{ +struct Foo +{ + Foo() noexcept(false); +}; +class Bar +{ + Bar(Bar&&) { Foo aFoo; } +}; + +class Bar2 +{ + Foo m_foo; + + Bar2(Bar2&&) {} +}; +}; + +// No warning expected, because calling throwing destructor. +namespace test4 +{ +struct Foo +{ + ~Foo() noexcept(false); +}; + +class Bar +{ + Bar(Bar&&) { Foo aFoo; } +}; +}; + +// Check for calls to defaulted constructors. +namespace test5 +{ +struct Foo +{ + Foo() = default; // non-throwing +}; +class Bar +{ + Bar(Bar&&) // expected-error {{move constructor can be noexcept [loplugin:noexceptmove]}} + { + Foo aFoo; + (void)aFoo; + } +}; +}; + +#else +// expected-no-diagnostics +#endif // CLANG_VERSION +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/connectivity/source/drivers/evoab2/NStatement.hxx b/connectivity/source/drivers/evoab2/NStatement.hxx index a36e524af5c2..14c12700ca62 100644 --- a/connectivity/source/drivers/evoab2/NStatement.hxx +++ b/connectivity/source/drivers/evoab2/NStatement.hxx @@ -82,7 +82,7 @@ namespace connectivity if (mpQuery) e_book_query_ref(mpQuery); } - EBookQueryWrapper(EBookQueryWrapper&& rhs) + EBookQueryWrapper(EBookQueryWrapper&& rhs) noexcept : mpQuery(rhs.mpQuery) { rhs.mpQuery = nullptr; diff --git a/cppu/source/uno/lbmap.cxx b/cppu/source/uno/lbmap.cxx index 6979c74042f9..a97d2a0dc829 100644 --- a/cppu/source/uno/lbmap.cxx +++ b/cppu/source/uno/lbmap.cxx @@ -60,13 +60,13 @@ class Mapping public: inline explicit Mapping( uno_Mapping * pMapping = nullptr ); inline Mapping( const Mapping & rMapping ); - Mapping(Mapping && other): _pMapping(other._pMapping) + Mapping(Mapping && other) noexcept : _pMapping(other._pMapping) { other._pMapping = nullptr; } inline ~Mapping(); inline Mapping & operator = ( uno_Mapping * pMapping ); Mapping & operator = ( const Mapping & rMapping ) { return operator = ( rMapping._pMapping ); } - Mapping & operator =(Mapping && other) { + Mapping & operator =(Mapping && other) noexcept { if (_pMapping != nullptr) { (*_pMapping->release)(_pMapping); } diff --git a/include/com/sun/star/uno/Reference.h b/include/com/sun/star/uno/Reference.h index 5f4c8ddea85f..50afd26a83b4 100644 --- a/include/com/sun/star/uno/Reference.h +++ b/include/com/sun/star/uno/Reference.h @@ -307,7 +307,7 @@ public: @param rRef another reference */ - inline Reference( Reference< interface_type > && rRef ); + inline Reference( Reference< interface_type > && rRef ) noexcept; #endif /** Up-casting conversion constructor: Copies interface reference. @@ -586,7 +586,7 @@ public: @param rRef an interface reference @return this reference */ - inline Reference< interface_type > & SAL_CALL operator = ( Reference< interface_type > && rRef ); + inline Reference< interface_type > & SAL_CALL operator = ( Reference< interface_type > && rRef ) noexcept; #endif /** Queries given interface reference for type interface_type. diff --git a/include/com/sun/star/uno/Reference.hxx b/include/com/sun/star/uno/Reference.hxx index c6869d922d7e..9edbd70d0f88 100644 --- a/include/com/sun/star/uno/Reference.hxx +++ b/include/com/sun/star/uno/Reference.hxx @@ -126,7 +126,7 @@ inline Reference< interface_type >::Reference( const Reference< interface_type > #if defined LIBO_INTERNAL_ONLY template< class interface_type > -inline Reference< interface_type >::Reference( Reference< interface_type > && rRef ) +inline Reference< interface_type >::Reference( Reference< interface_type > && rRef ) noexcept { _pInterface = rRef._pInterface; rRef._pInterface = nullptr; @@ -353,7 +353,7 @@ inline Reference< interface_type > & Reference< interface_type >::operator = ( #if defined LIBO_INTERNAL_ONLY template< class interface_type > inline Reference< interface_type > & Reference< interface_type >::operator = ( - Reference< interface_type > && rRef ) + Reference< interface_type > && rRef ) noexcept { if (_pInterface) _pInterface->release(); diff --git a/include/cppuhelper/weakref.hxx b/include/cppuhelper/weakref.hxx index cd05d3bee39b..c681284bac77 100644 --- a/include/cppuhelper/weakref.hxx +++ b/include/cppuhelper/weakref.hxx @@ -64,7 +64,7 @@ public: WeakReferenceHelper( const WeakReferenceHelper & rWeakRef ); #if defined LIBO_INTERNAL_ONLY - WeakReferenceHelper(WeakReferenceHelper && other): m_pImpl(other.m_pImpl) + WeakReferenceHelper(WeakReferenceHelper && other) noexcept : m_pImpl(other.m_pImpl) { other.m_pImpl = nullptr; } #endif diff --git a/include/osl/pipe.hxx b/include/osl/pipe.hxx index e9cfe2e6c3f0..50022b7545c8 100644 --- a/include/osl/pipe.hxx +++ b/include/osl/pipe.hxx @@ -51,7 +51,7 @@ namespace osl } #if defined LIBO_INTERNAL_ONLY - Pipe::Pipe(Pipe && other): m_handle(other.m_handle) { + Pipe::Pipe(Pipe && other) noexcept : m_handle(other.m_handle) { other.m_handle = nullptr; } #endif @@ -97,7 +97,7 @@ namespace osl } #if defined LIBO_INTERNAL_ONLY - Pipe & Pipe::operator =(Pipe && other) { + Pipe & Pipe::operator =(Pipe && other) noexcept { if (m_handle != nullptr) { osl_releasePipe(m_handle); } diff --git a/include/osl/pipe_decl.hxx b/include/osl/pipe_decl.hxx index 146b77a5624e..57f2c76b1c7c 100644 --- a/include/osl/pipe_decl.hxx +++ b/include/osl/pipe_decl.hxx @@ -59,7 +59,7 @@ public: inline Pipe(const Pipe& pipe); #if defined LIBO_INTERNAL_ONLY - inline Pipe(Pipe && other); + inline Pipe(Pipe && other) noexcept; #endif /** Constructs a Pipe reference without acquiring the handle @@ -108,7 +108,7 @@ public: inline Pipe& SAL_CALL operator= (const Pipe& pipe); #if defined LIBO_INTERNAL_ONLY - inline Pipe & operator =(Pipe && other); + inline Pipe & operator =(Pipe && other) noexcept; #endif /** Assignment operator. If pipe was already created, the old one will diff --git a/include/osl/socket.hxx b/include/osl/socket.hxx index 0227095df089..640880144177 100644 --- a/include/osl/socket.hxx +++ b/include/osl/socket.hxx @@ -35,7 +35,7 @@ namespace osl } #if defined LIBO_INTERNAL_ONLY - SocketAddr::SocketAddr(SocketAddr && other): m_handle(other.m_handle) { + SocketAddr::SocketAddr(SocketAddr && other) noexcept : m_handle(other.m_handle) { other.m_handle = nullptr; } #endif @@ -141,7 +141,7 @@ namespace osl } #if defined LIBO_INTERNAL_ONLY - SocketAddr & SocketAddr::operator =(SocketAddr && other) { + SocketAddr & SocketAddr::operator =(SocketAddr && other) noexcept { if (m_handle != nullptr) { osl_destroySocketAddr(m_handle); } diff --git a/include/osl/socket_decl.hxx b/include/osl/socket_decl.hxx index 3d2a05634348..25916897d0f9 100644 --- a/include/osl/socket_decl.hxx +++ b/include/osl/socket_decl.hxx @@ -51,7 +51,7 @@ namespace osl inline SocketAddr(const SocketAddr& Addr); #if defined LIBO_INTERNAL_ONLY - inline SocketAddr(SocketAddr && other); + inline SocketAddr(SocketAddr && other) noexcept; #endif /** The SocketAddr takes over the responsibility of the handle (which means @@ -141,7 +141,7 @@ namespace osl inline SocketAddr & SAL_CALL operator= (const SocketAddr& Addr); #if defined LIBO_INTERNAL_ONLY - inline SocketAddr & operator =(SocketAddr && other); + inline SocketAddr & operator =(SocketAddr && other) noexcept; #endif /** Assigns the socket addr without copyconstructing it. diff --git a/include/registry/registry.hxx b/include/registry/registry.hxx index 200d91b4f426..9e264f4a30bd 100644 --- a/include/registry/registry.hxx +++ b/include/registry/registry.hxx @@ -90,7 +90,7 @@ public: /// Copy constructor inline Registry(const Registry& toCopy); - Registry(Registry && other): m_pApi(other.m_pApi), m_hImpl(other.m_hImpl) + Registry(Registry && other) noexcept : m_pApi(other.m_pApi), m_hImpl(other.m_hImpl) { other.m_hImpl = nullptr; } /// Destructor. The Destructor close the registry if it is open. diff --git a/include/rtl/byteseq.h b/include/rtl/byteseq.h index 0ec93c066652..e47d60e83e00 100644 --- a/include/rtl/byteseq.h +++ b/include/rtl/byteseq.h @@ -190,7 +190,7 @@ public: */ inline ByteSequence( const ByteSequence & rSeq ); #if defined LIBO_INTERNAL_ONLY - inline ByteSequence( ByteSequence && rSeq ); + inline ByteSequence( ByteSequence && rSeq ) noexcept; #endif /** Copy constructor Creates a copy from the C-Handle. @@ -236,7 +236,7 @@ public: */ inline ByteSequence & SAL_CALL operator = ( const ByteSequence & rSeq ); #if defined LIBO_INTERNAL_ONLY - inline ByteSequence & SAL_CALL operator = ( ByteSequence && rSeq ); + inline ByteSequence & SAL_CALL operator = ( ByteSequence && rSeq ) noexcept; #endif /** Gets the length of sequence. diff --git a/include/rtl/byteseq.hxx b/include/rtl/byteseq.hxx index bf287830c77d..597e336e43ad 100644 --- a/include/rtl/byteseq.hxx +++ b/include/rtl/byteseq.hxx @@ -41,7 +41,7 @@ inline ByteSequence::ByteSequence( const ByteSequence & rSeq ) } #if defined LIBO_INTERNAL_ONLY -inline ByteSequence::ByteSequence( ByteSequence && rSeq ) +inline ByteSequence::ByteSequence( ByteSequence && rSeq ) noexcept : _pSequence(rSeq._pSequence) { rSeq._pSequence = nullptr; @@ -95,7 +95,7 @@ inline ByteSequence & ByteSequence::operator = ( const ByteSequence & rSeq ) } #if defined LIBO_INTERNAL_ONLY -inline ByteSequence & ByteSequence::operator = ( ByteSequence && rSeq ) +inline ByteSequence & ByteSequence::operator = ( ByteSequence && rSeq ) noexcept { ::rtl_byte_sequence_release(_pSequence); _pSequence = rSeq._pSequence; diff --git a/include/rtl/ref.hxx b/include/rtl/ref.hxx index 73c03ff7657d..b0324d99313d 100644 --- a/include/rtl/ref.hxx +++ b/include/rtl/ref.hxx @@ -77,7 +77,7 @@ public: #ifdef LIBO_INTERNAL_ONLY /** Move constructor... */ - Reference (Reference && handle) + Reference (Reference && handle) noexcept : m_pBody (handle.m_pBody) { handle.m_pBody = nullptr; diff --git a/include/rtl/string.hxx b/include/rtl/string.hxx index 3b33ee4f1ae5..d06a1b727394 100644 --- a/include/rtl/string.hxx +++ b/include/rtl/string.hxx @@ -129,7 +129,7 @@ public: @param str an OString. @since LibreOffice 5.2 */ - OString( OString && str ) + OString( OString && str ) noexcept { pData = str.pData; str.pData = nullptr; @@ -313,7 +313,7 @@ public: @param str an OString. @since LibreOffice 5.2 */ - OString & operator=( OString && str ) + OString & operator=( OString && str ) noexcept { rtl_string_release( pData ); pData = str.pData; diff --git a/include/rtl/ustring.hxx b/include/rtl/ustring.hxx index 8050e0af9c41..18b717fd2b04 100644 --- a/include/rtl/ustring.hxx +++ b/include/rtl/ustring.hxx @@ -158,7 +158,7 @@ public: @param str an OUString. @since LibreOffice 5.2 */ - OUString( OUString && str ) + OUString( OUString && str ) noexcept { pData = str.pData; str.pData = nullptr; @@ -462,7 +462,7 @@ public: @param str an OUString. @since LibreOffice 5.2 */ - OUString & operator=( OUString && str ) + OUString & operator=( OUString && str ) noexcept { rtl_uString_release( pData ); pData = str.pData; diff --git a/include/sfx2/objsh.hxx b/include/sfx2/objsh.hxx index a25d60aa2db1..53797278c056 100644 --- a/include/sfx2/objsh.hxx +++ b/include/sfx2/objsh.hxx @@ -778,7 +778,7 @@ protected: public: SfxObjectShellLock() { pObj = nullptr; } inline SfxObjectShellLock( const SfxObjectShellLock & rObj ); - inline SfxObjectShellLock( SfxObjectShellLock && rObj ); + inline SfxObjectShellLock( SfxObjectShellLock && rObj ) noexcept; inline SfxObjectShellLock( SfxObjectShell * pObjP ); inline void Clear(); inline ~SfxObjectShellLock(); @@ -797,7 +797,7 @@ inline SfxObjectShellLock::SfxObjectShellLock( const SfxObjectShellLock & rObj ) if( pObj ) pObj->OwnerLock( true ); } -inline SfxObjectShellLock::SfxObjectShellLock( SfxObjectShellLock && rObj ) +inline SfxObjectShellLock::SfxObjectShellLock( SfxObjectShellLock && rObj ) noexcept { pObj = rObj.pObj; rObj.pObj = nullptr; diff --git a/include/store/store.hxx b/include/store/store.hxx index fb4b430c5f2e..c4f4ce6db5fb 100644 --- a/include/store/store.hxx +++ b/include/store/store.hxx @@ -147,7 +147,7 @@ public: /** Move construction. */ - OStoreDirectory (OStoreDirectory && rhs) + OStoreDirectory (OStoreDirectory && rhs) noexcept : m_hImpl (rhs.m_hImpl) { rhs.m_hImpl = nullptr; @@ -167,7 +167,7 @@ public: /** Move assignment. */ - OStoreDirectory & operator= (OStoreDirectory && rhs) + OStoreDirectory & operator= (OStoreDirectory && rhs) noexcept { if (m_hImpl) (void) store_releaseHandle (m_hImpl); diff --git a/include/tools/globname.hxx b/include/tools/globname.hxx index 3280cb69a2f6..9672f444ccad 100644 --- a/include/tools/globname.hxx +++ b/include/tools/globname.hxx @@ -60,7 +60,7 @@ public: pImp( rObj.pImp ) { } - SvGlobalName( SvGlobalName && rObj ) : + SvGlobalName( SvGlobalName && rObj ) noexcept : pImp( std::move(rObj.pImp) ) { } @@ -75,7 +75,7 @@ public: SvGlobalName( const SvGUID & rId ); SvGlobalName & operator = ( const SvGlobalName & rObj ); - SvGlobalName & operator = ( SvGlobalName && rObj ); + SvGlobalName & operator = ( SvGlobalName && rObj ) noexcept; ~SvGlobalName(); TOOLS_DLLPUBLIC friend SvStream & operator >> ( SvStream &, SvGlobalName & ); diff --git a/include/tools/poly.hxx b/include/tools/poly.hxx index b0c6190b6eb8..aed40ece0367 100644 --- a/include/tools/poly.hxx +++ b/include/tools/poly.hxx @@ -98,7 +98,7 @@ public: sal_uInt16 nPoints ); Polygon( const tools::Polygon& rPoly ); - Polygon( tools::Polygon&& rPoly); + Polygon( tools::Polygon&& rPoly) noexcept; ~Polygon(); void SetPoint( const Point& rPt, sal_uInt16 nPos ); @@ -155,7 +155,7 @@ public: Point& operator[]( sal_uInt16 nPos ); tools::Polygon& operator=( const tools::Polygon& rPoly ); - tools::Polygon& operator=( tools::Polygon&& rPoly ); + tools::Polygon& operator=( tools::Polygon&& rPoly ) noexcept; bool operator==( const tools::Polygon& rPoly ) const; bool operator!=( const tools::Polygon& rPoly ) const { return !(Polygon::operator==( rPoly )); } diff --git a/include/typelib/typedescription.hxx b/include/typelib/typedescription.hxx index ae8599bb1fdd..bfe7596801ea 100644 --- a/include/typelib/typedescription.hxx +++ b/include/typelib/typedescription.hxx @@ -83,7 +83,7 @@ public: */ inline TypeDescription( const TypeDescription & rDescr ); #if defined LIBO_INTERNAL_ONLY - TypeDescription(TypeDescription && other): _pTypeDescr(other._pTypeDescr) + TypeDescription(TypeDescription && other) noexcept : _pTypeDescr(other._pTypeDescr) { other._pTypeDescr = nullptr; } #endif /** Constructor: @@ -115,7 +115,7 @@ public: { return this->operator =( rTypeDescr.get() ); } #if defined LIBO_INTERNAL_ONLY - TypeDescription & operator =(TypeDescription && other) { + TypeDescription & operator =(TypeDescription && other) noexcept { if (_pTypeDescr != nullptr) { typelib_typedescription_release(_pTypeDescr); } diff --git a/include/uno/dispatcher.hxx b/include/uno/dispatcher.hxx index bfd00d46b374..f23268e55593 100644 --- a/include/uno/dispatcher.hxx +++ b/include/uno/dispatcher.hxx @@ -59,7 +59,7 @@ public: inline UnoInterfaceReference( UnoInterfaceReference const & ref ); #if defined LIBO_INTERNAL_ONLY - UnoInterfaceReference(UnoInterfaceReference && other): + UnoInterfaceReference(UnoInterfaceReference && other) noexcept : m_pUnoI(other.m_pUnoI) { other.m_pUnoI = nullptr; } #endif diff --git a/include/uno/environment.hxx b/include/uno/environment.hxx index 5d5ef86021ef..0484790cfa36 100644 --- a/include/uno/environment.hxx +++ b/include/uno/environment.hxx @@ -95,7 +95,7 @@ public: inline Environment( const Environment & rEnv ); #if defined LIBO_INTERNAL_ONLY - Environment(Environment && other): _pEnv(other._pEnv) + Environment(Environment && other) noexcept : _pEnv(other._pEnv) { other._pEnv = nullptr; } #endif diff --git a/include/uno/mapping.hxx b/include/uno/mapping.hxx index a575f251539f..be21909eb5c6 100644 --- a/include/uno/mapping.hxx +++ b/include/uno/mapping.hxx @@ -111,7 +111,7 @@ public: inline Mapping( const Mapping & rMapping ); #if defined LIBO_INTERNAL_ONLY - Mapping(Mapping && other): _pMapping(other._pMapping) + Mapping(Mapping && other) noexcept : _pMapping(other._pMapping) { other._pMapping = nullptr; } #endif @@ -134,7 +134,7 @@ public: { return operator = ( rMapping._pMapping ); } #if defined LIBO_INTERNAL_ONLY - Mapping & operator =(Mapping && other) { + Mapping & operator =(Mapping && other) noexcept { if (_pMapping != nullptr) { (*_pMapping->release)(_pMapping); } diff --git a/include/unotools/itemholderbase.hxx b/include/unotools/itemholderbase.hxx index b401de3435c1..eeb5fa6ee9c0 100644 --- a/include/unotools/itemholderbase.hxx +++ b/include/unotools/itemholderbase.hxx @@ -83,7 +83,7 @@ struct TItemInfo { } - TItemInfo(TItemInfo&& other) + TItemInfo(TItemInfo&& other) noexcept : pItem(std::move(other.pItem)) , eItem(other.eItem) { diff --git a/include/unotools/tempfile.hxx b/include/unotools/tempfile.hxx index b77d6e3a798f..b20a4f2fdf40 100644 --- a/include/unotools/tempfile.hxx +++ b/include/unotools/tempfile.hxx @@ -71,7 +71,7 @@ public: TempFile( const OUString& rLeadingChars, bool _bStartWithZero=true, const OUString* pExtension=nullptr, const OUString* pParent=nullptr, bool bCreateParentDirs=false ); - TempFile(TempFile && other); + TempFile(TempFile && other) noexcept; /** TempFile will be removed from disk in dtor if EnableKillingFile(true) was called before. diff --git a/include/vcl/alpha.hxx b/include/vcl/alpha.hxx index b0ea775e1516..f87ac133970a 100644 --- a/include/vcl/alpha.hxx +++ b/include/vcl/alpha.hxx @@ -42,7 +42,7 @@ public: AlphaMask& operator=( const Bitmap& rBitmap ); AlphaMask& operator=( const AlphaMask& rAlphaMask ) { return static_cast( Bitmap::operator=( rAlphaMask ) ); } - AlphaMask& operator=( AlphaMask&& rAlphaMask ) { return static_cast( Bitmap::operator=( std::move(rAlphaMask) ) ); } + AlphaMask& operator=( AlphaMask&& rAlphaMask ) noexcept { return static_cast( Bitmap::operator=( std::move(rAlphaMask) ) ); } bool operator!() const { return Bitmap::operator!(); } bool operator==( const AlphaMask& rAlphaMask ) const { return Bitmap::operator==(rAlphaMask); } bool operator!=( const AlphaMask& rAlphaMask ) const { return Bitmap::operator!=(rAlphaMask); } diff --git a/include/vcl/font.hxx b/include/vcl/font.hxx index 34ccf2ab5dd4..ac8c6d4c2153 100644 --- a/include/vcl/font.hxx +++ b/include/vcl/font.hxx @@ -48,7 +48,7 @@ class VCL_DLLPUBLIC Font public: explicit Font(); Font( const Font& ); // TODO make me explicit - Font( Font&& ); + Font( Font&& ) noexcept; explicit Font( const OUString& rFamilyName, const Size& ); explicit Font( const OUString& rFamilyName, const OUString& rStyleName, const Size& ); explicit Font( FontFamily eFamily, const Size& ); @@ -150,7 +150,7 @@ public: void GetFontAttributes( FontAttributes& rAttrs ) const; Font& operator=( const Font& ); - Font& operator=( Font&& ); + Font& operator=( Font&& ) noexcept; bool operator==( const Font& ) const; bool operator!=( const Font& rFont ) const { return !(Font::operator==( rFont )); } diff --git a/include/vcl/region.hxx b/include/vcl/region.hxx index 3edcaa033636..faa2da61141d 100644 --- a/include/vcl/region.hxx +++ b/include/vcl/region.hxx @@ -72,7 +72,7 @@ public: explicit Region(const tools::PolyPolygon& rPolyPoly); explicit Region(const basegfx::B2DPolyPolygon&); Region(const vcl::Region& rRegion); - Region(vcl::Region&& rRegion); + Region(vcl::Region&& rRegion) noexcept; ~Region(); // direct access to contents @@ -114,7 +114,7 @@ public: bool IsOver( const tools::Rectangle& rRect ) const; vcl::Region& operator=( const vcl::Region& rRegion ); - vcl::Region& operator=( vcl::Region&& rRegion ); + vcl::Region& operator=( vcl::Region&& rRegion ) noexcept; vcl::Region& operator=( const tools::Rectangle& rRect ); bool operator==( const vcl::Region& rRegion ) const; diff --git a/solenv/CompilerTest_compilerplugins_clang.mk b/solenv/CompilerTest_compilerplugins_clang.mk index b791e5985587..167433f7974c 100644 --- a/solenv/CompilerTest_compilerplugins_clang.mk +++ b/solenv/CompilerTest_compilerplugins_clang.mk @@ -38,6 +38,7 @@ $(eval $(call gb_CompilerTest_add_exception_objects,compilerplugins_clang, \ compilerplugins/clang/test/loopvartoosmall \ compilerplugins/clang/test/nullptr \ compilerplugins/clang/test/mapindex \ + compilerplugins/clang/test/noexceptmove \ compilerplugins/clang/test/oncevar \ compilerplugins/clang/test/oslendian-1 \ compilerplugins/clang/test/oslendian-2 \ diff --git a/sw/inc/IDocumentMarkAccess.hxx b/sw/inc/IDocumentMarkAccess.hxx index a347c81d5bb3..4d12a236a4f1 100644 --- a/sw/inc/IDocumentMarkAccess.hxx +++ b/sw/inc/IDocumentMarkAccess.hxx @@ -76,8 +76,8 @@ class IDocumentMarkAccess iterator(std::vector<::sw::mark::MarkBase*>::const_iterator const& rIter); iterator(iterator const& rOther); iterator& operator=(iterator const& rOther); - iterator(iterator && rOther); - iterator& operator=(iterator && rOther); + iterator(iterator && rOther) noexcept; + iterator& operator=(iterator && rOther) noexcept; ~iterator(); // FIXME unfortunately there's a requirement on input iterator diff --git a/sw/source/core/doc/docbm.cxx b/sw/source/core/doc/docbm.cxx index 46b1d0ffb372..deb1048da936 100644 --- a/sw/source/core/doc/docbm.cxx +++ b/sw/source/core/doc/docbm.cxx @@ -80,12 +80,12 @@ auto IDocumentMarkAccess::iterator::operator=(iterator const& rOther) -> iterato return *this; } -IDocumentMarkAccess::iterator::iterator(iterator && rOther) +IDocumentMarkAccess::iterator::iterator(iterator && rOther) noexcept : m_pIter(std::move(rOther.m_pIter)) { } -auto IDocumentMarkAccess::iterator::operator=(iterator && rOther) -> iterator& +auto IDocumentMarkAccess::iterator::operator=(iterator && rOther) noexcept -> iterator& { m_pIter = std::move(rOther.m_pIter); return *this; diff --git a/tools/source/generic/poly.cxx b/tools/source/generic/poly.cxx index 6f2d3115dfcf..0a597fdff1fc 100644 --- a/tools/source/generic/poly.cxx +++ b/tools/source/generic/poly.cxx @@ -872,7 +872,7 @@ Polygon::Polygon( const tools::Polygon& rPoly ) : mpImplPolygon(rPoly.mpImplPoly { } -Polygon::Polygon( tools::Polygon&& rPoly) +Polygon::Polygon( tools::Polygon&& rPoly) noexcept : mpImplPolygon(std::move(rPoly.mpImplPolygon)) { } @@ -1555,7 +1555,7 @@ tools::Polygon& Polygon::operator=( const tools::Polygon& rPoly ) return *this; } -tools::Polygon& Polygon::operator=( tools::Polygon&& rPoly ) +tools::Polygon& Polygon::operator=( tools::Polygon&& rPoly ) noexcept { mpImplPolygon = std::move(rPoly.mpImplPolygon); return *this; diff --git a/tools/source/ref/globname.cxx b/tools/source/ref/globname.cxx index 47f1da1577e5..0a87bcf17b5d 100644 --- a/tools/source/ref/globname.cxx +++ b/tools/source/ref/globname.cxx @@ -105,7 +105,7 @@ SvGlobalName & SvGlobalName::operator = ( const SvGlobalName & rObj ) return *this; } -SvGlobalName & SvGlobalName::operator = ( SvGlobalName && rObj ) +SvGlobalName & SvGlobalName::operator = ( SvGlobalName && rObj ) noexcept { pImp = std::move(rObj.pImp); return *this; diff --git a/unotools/source/ucbhelper/tempfile.cxx b/unotools/source/ucbhelper/tempfile.cxx index 83c2effa919e..bce71120f4f9 100644 --- a/unotools/source/ucbhelper/tempfile.cxx +++ b/unotools/source/ucbhelper/tempfile.cxx @@ -370,7 +370,7 @@ TempFile::TempFile( const OUString& rLeadingChars, bool _bStartWithZero, true, true, bCreateParentDirs ); } -TempFile::TempFile(TempFile && other): +TempFile::TempFile(TempFile && other) noexcept : aName(std::move(other.aName)), pStream(std::move(other.pStream)), bIsDirectory(other.bIsDirectory), bKillingFileEnabled(other.bKillingFileEnabled) { diff --git a/vcl/source/font/font.cxx b/vcl/source/font/font.cxx index 914ea9880b82..1d3528b0d7d2 100644 --- a/vcl/source/font/font.cxx +++ b/vcl/source/font/font.cxx @@ -49,7 +49,7 @@ Font::Font( const vcl::Font& rFont ) : mpImplFont( rFont.mpImplFont ) { } -Font::Font( vcl::Font&& rFont ) : mpImplFont( std::move(rFont.mpImplFont) ) +Font::Font( vcl::Font&& rFont ) noexcept : mpImplFont( std::move(rFont.mpImplFont) ) { } @@ -283,7 +283,7 @@ Font& Font::operator=( const vcl::Font& rFont ) return *this; } -Font& Font::operator=( vcl::Font&& rFont ) +Font& Font::operator=( vcl::Font&& rFont ) noexcept { mpImplFont = std::move(rFont.mpImplFont); return *this; diff --git a/vcl/source/gdi/region.cxx b/vcl/source/gdi/region.cxx index 983d76305fa9..4f830a2195e8 100644 --- a/vcl/source/gdi/region.cxx +++ b/vcl/source/gdi/region.cxx @@ -365,7 +365,7 @@ Region::Region(const basegfx::B2DPolyPolygon& rPolyPoly) Region::Region(const vcl::Region&) = default; -Region::Region(vcl::Region&& rRegion) +Region::Region(vcl::Region&& rRegion) noexcept : mpB2DPolyPolygon(std::move(rRegion.mpB2DPolyPolygon)), mpPolyPolygon(std::move(rRegion.mpPolyPolygon)), mpRegionBand(std::move(rRegion.mpRegionBand)), @@ -1425,7 +1425,7 @@ void vcl::Region::SetEmpty() Region& vcl::Region::operator=( const vcl::Region& ) = default; -Region& vcl::Region::operator=( vcl::Region&& rRegion ) +Region& vcl::Region::operator=( vcl::Region&& rRegion ) noexcept { mpB2DPolyPolygon = std::move(rRegion.mpB2DPolyPolygon); mpPolyPolygon = std::move(rRegion.mpPolyPolygon); -- 2.11.4.GIT