diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp @@ -14,6 +14,7 @@ #include "../modernize/AvoidCArraysCheck.h" #include "../modernize/UseDefaultMemberInitCheck.h" #include "../modernize/UseOverrideCheck.h" +#include "../performance/NoexceptSpecialFunctionsCheck.h" #include "../readability/MagicNumbersCheck.h" #include "AvoidCapturingLambdaCoroutinesCheck.h" #include "AvoidConstOrRefDataMembersCheck.h" @@ -80,6 +81,8 @@ CheckFactories.registerCheck( "cppcoreguidelines-narrowing-conversions"); CheckFactories.registerCheck("cppcoreguidelines-no-malloc"); + CheckFactories.registerCheck( + "cppcoreguidelines-noexcept-special-functions"); CheckFactories.registerCheck( "cppcoreguidelines-non-private-member-variables-in-classes"); CheckFactories.registerCheck( diff --git a/clang-tools-extra/clang-tidy/hicpp/HICPPTidyModule.cpp b/clang-tools-extra/clang-tidy/hicpp/HICPPTidyModule.cpp --- a/clang-tools-extra/clang-tidy/hicpp/HICPPTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/hicpp/HICPPTidyModule.cpp @@ -31,7 +31,7 @@ #include "../modernize/UseNullptrCheck.h" #include "../modernize/UseOverrideCheck.h" #include "../performance/MoveConstArgCheck.h" -#include "../performance/NoexceptMoveConstructorCheck.h" +#include "../performance/NoexceptSpecialFunctionsCheck.h" #include "../readability/BracesAroundStatementsCheck.h" #include "../readability/FunctionSizeCheck.h" #include "../readability/NamedParameterCheck.h" @@ -74,7 +74,7 @@ "hicpp-move-const-arg"); CheckFactories.registerCheck( "hicpp-new-delete-operators"); - CheckFactories.registerCheck( + CheckFactories.registerCheck( "hicpp-noexcept-move"); CheckFactories .registerCheck( diff --git a/clang-tools-extra/clang-tidy/performance/CMakeLists.txt b/clang-tools-extra/clang-tidy/performance/CMakeLists.txt --- a/clang-tools-extra/clang-tidy/performance/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/performance/CMakeLists.txt @@ -14,7 +14,7 @@ MoveConstructorInitCheck.cpp NoAutomaticMoveCheck.cpp NoIntToPtrCheck.cpp - NoexceptMoveConstructorCheck.cpp + NoexceptSpecialFunctionsCheck.cpp PerformanceTidyModule.cpp TriviallyDestructibleCheck.cpp TypePromotionInMathFnCheck.cpp diff --git a/clang-tools-extra/clang-tidy/performance/NoexceptMoveConstructorCheck.cpp b/clang-tools-extra/clang-tidy/performance/NoexceptMoveConstructorCheck.cpp deleted file mode 100644 --- a/clang-tools-extra/clang-tidy/performance/NoexceptMoveConstructorCheck.cpp +++ /dev/null @@ -1,72 +0,0 @@ -//===--- NoexceptMoveConstructorCheck.cpp - clang-tidy---------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "NoexceptMoveConstructorCheck.h" -#include "clang/AST/ASTContext.h" -#include "clang/ASTMatchers/ASTMatchFinder.h" -#include "clang/Lex/Lexer.h" -#include "clang/Tooling/FixIt.h" - -using namespace clang::ast_matchers; - -namespace clang::tidy::performance { - -void NoexceptMoveConstructorCheck::registerMatchers(MatchFinder *Finder) { - Finder->addMatcher( - cxxMethodDecl(unless(isImplicit()), unless(isDeleted()), - anyOf(cxxConstructorDecl(isMoveConstructor()), - isMoveAssignmentOperator())) - .bind("decl"), - this); -} - -void NoexceptMoveConstructorCheck::check( - const MatchFinder::MatchResult &Result) { - const auto *Decl = Result.Nodes.getNodeAs("decl"); - if (!Decl) - return; - - if (SpecAnalyzer.analyze(Decl) != - utils::ExceptionSpecAnalyzer::State::Throwing) - return; - - const bool IsConstructor = CXXConstructorDecl::classof(Decl); - - // Don't complain about nothrow(false), but complain on nothrow(expr) - // where expr evaluates to false. - const auto *ProtoType = Decl->getType()->castAs(); - const Expr *NoexceptExpr = ProtoType->getNoexceptExpr(); - if (NoexceptExpr) { - NoexceptExpr = NoexceptExpr->IgnoreImplicit(); - if (!isa(NoexceptExpr)) { - diag(NoexceptExpr->getExprLoc(), - "noexcept specifier on the move %select{assignment " - "operator|constructor}0 evaluates to 'false'") - << IsConstructor; - } - return; - } - - auto Diag = diag(Decl->getLocation(), - "move %select{assignment operator|constructor}0s should " - "be marked noexcept") - << IsConstructor; - // Add FixIt hints. - const SourceManager &SM = *Result.SourceManager; - assert(Decl->getNumParams() > 0); - SourceLocation NoexceptLoc = - Decl->getParamDecl(Decl->getNumParams() - 1)->getSourceRange().getEnd(); - if (NoexceptLoc.isValid()) - NoexceptLoc = Lexer::findLocationAfterToken( - NoexceptLoc, tok::r_paren, SM, Result.Context->getLangOpts(), true); - if (NoexceptLoc.isValid()) - Diag << FixItHint::CreateInsertion(NoexceptLoc, " noexcept "); - return; -} - -} // namespace clang::tidy::performance diff --git a/clang-tools-extra/clang-tidy/performance/NoexceptMoveConstructorCheck.h b/clang-tools-extra/clang-tidy/performance/NoexceptSpecialFunctionsCheck.h rename from clang-tools-extra/clang-tidy/performance/NoexceptMoveConstructorCheck.h rename to clang-tools-extra/clang-tidy/performance/NoexceptSpecialFunctionsCheck.h --- a/clang-tools-extra/clang-tidy/performance/NoexceptMoveConstructorCheck.h +++ b/clang-tools-extra/clang-tidy/performance/NoexceptSpecialFunctionsCheck.h @@ -1,4 +1,4 @@ -//===--- NoexceptMoveConstructorCheck.h - clang-tidy-------------*- C++ -*-===// +//===--- NoexceptSpecialFunctionsCheck.h - clang-tidy------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_NOEXCEPTMOVECONSTRUCTORCHECK_H -#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_NOEXCEPTMOVECONSTRUCTORCHECK_H +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_NOEXCEPTSPECIALFUNCTIONSCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_NOEXCEPTSPECIALFUNCTIONSCHECK_H #include "../ClangTidyCheck.h" #include "../utils/ExceptionSpecAnalyzer.h" @@ -21,9 +21,9 @@ /// Move constructors of all the types used with STL containers, for example, /// need to be declared `noexcept`. Otherwise STL will choose copy constructors /// instead. The same is valid for move assignment operations. -class NoexceptMoveConstructorCheck : public ClangTidyCheck { +class NoexceptSpecialFunctionsCheck : public ClangTidyCheck { public: - NoexceptMoveConstructorCheck(StringRef Name, ClangTidyContext *Context) + NoexceptSpecialFunctionsCheck(StringRef Name, ClangTidyContext *Context) : ClangTidyCheck(Name, Context) {} bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { return LangOpts.CPlusPlus11 && LangOpts.CXXExceptions; @@ -37,4 +37,4 @@ } // namespace clang::tidy::performance -#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_NOEXCEPTMOVECONSTRUCTORCHECK_H +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_NOEXCEPTSPECIALFUNCTIONSCHECK_H diff --git a/clang-tools-extra/clang-tidy/performance/NoexceptSpecialFunctionsCheck.cpp b/clang-tools-extra/clang-tidy/performance/NoexceptSpecialFunctionsCheck.cpp new file mode 100644 --- /dev/null +++ b/clang-tools-extra/clang-tidy/performance/NoexceptSpecialFunctionsCheck.cpp @@ -0,0 +1,125 @@ +//===--- NoexceptSpecialFunctionsCheck.cpp - clang-tidy--------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "NoexceptSpecialFunctionsCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Lex/Lexer.h" +#include "clang/Tooling/FixIt.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::performance { + +namespace { +StringRef getSpecialFunctionName(const FunctionDecl *FuncDecl) { + assert(FuncDecl); + + if (const auto *MethodDecl = dyn_cast(FuncDecl)) { + if (const auto *Ctor = dyn_cast(FuncDecl)) { + if (Ctor->isDefaultConstructor()) + return "default constructor"; + + if (Ctor->isMoveConstructor()) + return "move constructor"; + } + + if (MethodDecl->isMoveAssignmentOperator()) + return "move assignment operator"; + + if (isa(FuncDecl)) + return "destructor"; + } + + assert(FuncDecl->getName() == "swap"); + return "swap function"; +} + +SourceLocation getNoexceptLoc(const FunctionDecl *FuncDecl, + const SourceManager &SM) { + assert(FuncDecl); + + const LangOptions &LangOpts = FuncDecl->getLangOpts(); + + if (FuncDecl->getNumParams() == 0) { + // Start at the beginning of the function declaration, and find the closing + // parenthesis after which we would place the noexcept specifier. + Token CurrentToken; + SourceLocation CurrentLocation = FuncDecl->getBeginLoc(); + while (!Lexer::getRawToken(CurrentLocation, CurrentToken, SM, LangOpts, + true)) { + if (CurrentToken.is(tok::r_paren)) + return CurrentLocation.getLocWithOffset(1); + + CurrentLocation = CurrentToken.getEndLoc(); + } + + // Failed to find the closing parenthesis, so just return an invalid + // SourceLocation. + return {}; + } + + // FunctionDecl with parameters + SourceLocation NoexceptLoc = + FuncDecl->getParamDecl(FuncDecl->getNumParams() - 1)->getEndLoc(); + if (NoexceptLoc.isValid()) + return Lexer::findLocationAfterToken(NoexceptLoc, tok::r_paren, SM, + LangOpts, true); + + return {}; +} +} // namespace + +void NoexceptSpecialFunctionsCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher( + functionDecl(unless(isImplicit()), unless(isDeleted()), + anyOf(cxxDestructorDecl(), + cxxConstructorDecl(anyOf(isMoveConstructor(), + isDefaultConstructor())), + cxxMethodDecl(isMoveAssignmentOperator()), + hasName("swap"))) + .bind("decl"), + this); +} + +void NoexceptSpecialFunctionsCheck::check( + const MatchFinder::MatchResult &Result) { + const auto *FuncDecl = Result.Nodes.getNodeAs("decl"); + assert(FuncDecl); + + if (SpecAnalyzer.analyze(FuncDecl) != + utils::ExceptionSpecAnalyzer::State::Throwing) + return; + + // Don't complain about nothrow(false), but complain on nothrow(expr) + // where expr evaluates to false. + const auto *ProtoType = FuncDecl->getType()->castAs(); + const Expr *NoexceptExpr = ProtoType->getNoexceptExpr(); + if (NoexceptExpr) { + NoexceptExpr = NoexceptExpr->IgnoreImplicit(); + if (!isa(NoexceptExpr)) { + diag(NoexceptExpr->getExprLoc(), + "noexcept specifier on the %0 evaluates to 'false'") + << getSpecialFunctionName(FuncDecl); + } + return; + } + + auto Diag = diag(FuncDecl->getLocation(), "%0 should " + "be marked noexcept") + << getSpecialFunctionName(FuncDecl); + + // Add FixIt hints. + const SourceManager &SM = *Result.SourceManager; + + const SourceLocation NoexceptLoc = getNoexceptLoc(FuncDecl, SM); + if (NoexceptLoc.isValid()) + Diag << FixItHint::CreateInsertion(NoexceptLoc, " noexcept "); +} + +} // namespace clang::tidy::performance diff --git a/clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp b/clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp --- a/clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp @@ -19,7 +19,7 @@ #include "MoveConstructorInitCheck.h" #include "NoAutomaticMoveCheck.h" #include "NoIntToPtrCheck.h" -#include "NoexceptMoveConstructorCheck.h" +#include "NoexceptSpecialFunctionsCheck.h" #include "TriviallyDestructibleCheck.h" #include "TypePromotionInMathFnCheck.h" #include "UnnecessaryCopyInitialization.h" @@ -50,8 +50,8 @@ CheckFactories.registerCheck( "performance-no-automatic-move"); CheckFactories.registerCheck("performance-no-int-to-ptr"); - CheckFactories.registerCheck( - "performance-noexcept-move-constructor"); + CheckFactories.registerCheck( + "performance-noexcept-special-functions"); CheckFactories.registerCheck( "performance-trivially-destructible"); CheckFactories.registerCheck( diff --git a/clang-tools-extra/clang-tidy/utils/ExceptionSpecAnalyzer.cpp b/clang-tools-extra/clang-tidy/utils/ExceptionSpecAnalyzer.cpp --- a/clang-tools-extra/clang-tidy/utils/ExceptionSpecAnalyzer.cpp +++ b/clang-tools-extra/clang-tidy/utils/ExceptionSpecAnalyzer.cpp @@ -134,6 +134,11 @@ if (isUnresolvedExceptionSpec(FuncProto->getExceptionSpecType())) return State::Unknown; + // A non defaulted destructor without the noexcept specifier is still noexcept + if (isa(FuncDecl) && + FuncDecl->getExceptionSpecType() == EST_None) + return State::NotThrowing; + switch (FuncProto->canThrow()) { case CT_Cannot: return State::NotThrowing; diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -174,6 +174,12 @@ ` to :doc:`bugprone-unsafe-functions ` was added. +- New alias :doc:`cppcoreguidelines-noexcept-special-functions + ` to + :doc:`performance-noexcept-special-functions + ` + was added. + - New alias :doc:`cppcoreguidelines-use-default-member-init ` to :doc:`modernize-use-default-member-init @@ -334,10 +340,14 @@ ` to understand that there is a sequence point between designated initializers. -- Fixed an issue in the :doc:`performance-noexcept-move-constructor - ` checker that was causing +- Fixed an issue in the :doc:`performance-noexcept-special-functions + ` checker that was causing false-positives when the move constructor or move assign operator were defaulted. +- Improved :doc:`performance-noexcept-special-functions + ` to also handle + default constructors, destructors and swap functions. + - Fixed an issue in :doc:`readability-identifier-naming ` when specifying an empty string for ``Prefix`` or ``Suffix`` options could result in the style not diff --git a/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/noexcept-special-functions.rst b/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/noexcept-special-functions.rst new file mode 100644 --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/noexcept-special-functions.rst @@ -0,0 +1,10 @@ +.. title:: clang-tidy - cppcoreguidelines-noexcept-special-functions +.. meta:: + :http-equiv=refresh: 5;URL=../performance/noexcept-special-functions.html + +cppcoreguidelines-noexcept-special-functions +============================================ + +The cppcoreguidelines-noexcept-special-functions check is an alias, please see +`performance-noexcept-special-functions <../performance/noexcept-special-functions.html>`_ +for more information. diff --git a/clang-tools-extra/docs/clang-tidy/checks/hicpp/noexcept-move.rst b/clang-tools-extra/docs/clang-tidy/checks/hicpp/noexcept-move.rst --- a/clang-tools-extra/docs/clang-tidy/checks/hicpp/noexcept-move.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/hicpp/noexcept-move.rst @@ -1,9 +1,9 @@ .. title:: clang-tidy - hicpp-noexcept-move .. meta:: - :http-equiv=refresh: 5;URL=../performance/noexcept-move-constructor.html + :http-equiv=refresh: 5;URL=../performance/noexcept-special-functions.html hicpp-noexcept-move =================== -This check is an alias for `performance-noexcept-move-constructor <../performance/noexcept-move-constructor.html>`_. +This check is an alias for `performance-noexcept-special-functions <../performance/noexcept-special-functions.html>`_. Checks `rule 12.5.4 `_ to mark move assignment and move construction `noexcept`. diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -192,6 +192,7 @@ `cppcoreguidelines-misleading-capture-default-by-value `_, "Yes" `cppcoreguidelines-narrowing-conversions `_, `cppcoreguidelines-no-malloc `_, + `cppcoreguidelines-noexcept-special-functions `_, "Yes" `cppcoreguidelines-owning-memory `_, `cppcoreguidelines-prefer-member-initializer `_, "Yes" `cppcoreguidelines-pro-bounds-array-to-pointer-decay `_, @@ -324,7 +325,7 @@ `performance-move-constructor-init `_, `performance-no-automatic-move `_, `performance-no-int-to-ptr `_, - `performance-noexcept-move-constructor `_, "Yes" + `performance-noexcept-special-functions `_, "Yes" `performance-trivially-destructible `_, "Yes" `performance-type-promotion-in-math-fn `_, "Yes" `performance-unnecessary-copy-initialization `_, "Yes" @@ -494,7 +495,7 @@ `hicpp-new-delete-operators `_, `misc-new-delete-overloads `_, `hicpp-no-array-decay `_, `cppcoreguidelines-pro-bounds-array-to-pointer-decay `_, `hicpp-no-malloc `_, `cppcoreguidelines-no-malloc `_, - `hicpp-noexcept-move `_, `performance-noexcept-move-constructor `_, "Yes" + `hicpp-noexcept-move `_, `performance-noexcept-special-functions `_, "Yes" `hicpp-special-member-functions `_, `cppcoreguidelines-special-member-functions `_, `hicpp-static-assert `_, `misc-static-assert `_, "Yes" `hicpp-undelegated-constructor `_, `bugprone-undelegated-constructor `_, diff --git a/clang-tools-extra/docs/clang-tidy/checks/performance/noexcept-move-constructor.rst b/clang-tools-extra/docs/clang-tidy/checks/performance/noexcept-special-functions.rst rename from clang-tools-extra/docs/clang-tidy/checks/performance/noexcept-move-constructor.rst rename to clang-tools-extra/docs/clang-tidy/checks/performance/noexcept-special-functions.rst --- a/clang-tools-extra/docs/clang-tidy/checks/performance/noexcept-move-constructor.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/performance/noexcept-special-functions.rst @@ -1,10 +1,11 @@ -.. title:: clang-tidy - performance-noexcept-move-constructor +.. title:: clang-tidy - performance-noexcept-special-functions -performance-noexcept-move-constructor -===================================== +performance-noexcept-special-functions +====================================== -The check flags user-defined move constructors and assignment operators not +The check flags user-defined default constructors, move constructors, +assignment operators, destructors and swap functions not marked with ``noexcept`` or marked with ``noexcept(expr)`` where ``expr`` evaluates to ``false`` (but is not a ``false`` literal itself). diff --git a/clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-move-constructor.cpp b/clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-move-constructor.cpp deleted file mode 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-move-constructor.cpp +++ /dev/null @@ -1,378 +0,0 @@ -// RUN: %check_clang_tidy %s performance-noexcept-move-constructor %t -- -- -fexceptions - -struct Empty -{}; - -struct IntWrapper { - int value; -}; - -template -struct FalseT { - static constexpr bool value = false; -}; - -template -struct TrueT { - static constexpr bool value = true; -}; - -struct ThrowingMoveConstructor -{ - ThrowingMoveConstructor() = default; - ThrowingMoveConstructor(ThrowingMoveConstructor&&) noexcept(false) { - } - ThrowingMoveConstructor& operator=(ThrowingMoveConstructor &&) noexcept(false) { - return *this; - } -}; - -class A { - A(A &&); - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructors should be marked noexcept [performance-noexcept-move-constructor] - A &operator=(A &&); - // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operators should be marked noexcept [performance-noexcept-move-constructor] -}; - -struct B { - static constexpr bool kFalse = false; - B(B &&) noexcept(kFalse); - // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: noexcept specifier on the move constructor evaluates to 'false' [performance-noexcept-move-constructor] -}; - -template -struct C -{ - C(C &&); - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructors should be marked noexcept [performance-noexcept-move-constructor] - C& operator=(C &&); - // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operators should be marked noexcept [performance-noexcept-move-constructor] -}; - -struct D -{ - static constexpr bool kFalse = false; - D(D &&) noexcept(kFalse) = default; - // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: noexcept specifier on the move constructor evaluates to 'false' [performance-noexcept-move-constructor] - D& operator=(D &&) noexcept(kFalse) = default; - // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: noexcept specifier on the move assignment operator evaluates to 'false' -}; - -template -struct E -{ - static constexpr bool kFalse = false; - E(E &&) noexcept(kFalse); - // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: noexcept specifier on the move constructor evaluates to 'false' [performance-noexcept-move-constructor] - E& operator=(E &&) noexcept(kFalse); - // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: noexcept specifier on the move assignment operator evaluates to 'false' -}; - -template -struct F -{ - static constexpr bool kFalse = false; - F(F &&) noexcept(kFalse) = default; - // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: noexcept specifier on the move constructor evaluates to 'false' [performance-noexcept-move-constructor] - F& operator=(F &&) noexcept(kFalse) = default; - // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: noexcept specifier on the move assignment operator evaluates to 'false' -}; - -struct G { - G(G &&) = default; - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructors should be marked noexcept [performance-noexcept-move-constructor] - G& operator=(G &&) = default; - // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operators should be marked noexcept [performance-noexcept-move-constructor] - - ThrowingMoveConstructor field; -}; - -void throwing_function() noexcept(false) {} - -struct H { - H(H &&) noexcept(noexcept(throwing_function())); - // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: noexcept specifier on the move constructor evaluates to 'false' [performance-noexcept-move-constructor] - H &operator=(H &&) noexcept(noexcept(throwing_function())); - // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: noexcept specifier on the move assignment operator evaluates to 'false' -}; - -template -struct I { - I(I &&) noexcept(noexcept(throwing_function())); - // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: noexcept specifier on the move constructor evaluates to 'false' [performance-noexcept-move-constructor] - I &operator=(I &&) noexcept(noexcept(throwing_function())); - // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: noexcept specifier on the move assignment operator evaluates to 'false' -}; - -template struct TemplatedType { - static void f() {} -}; - -template <> struct TemplatedType { - static void f() noexcept {} -}; - -struct J { - J(J &&) noexcept(noexcept(TemplatedType::f())); - // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: noexcept specifier on the move constructor evaluates to 'false' [performance-noexcept-move-constructor] - J &operator=(J &&) noexcept(noexcept(TemplatedType::f())); - // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: noexcept specifier on the move assignment operator evaluates to 'false' [performance-noexcept-move-constructor] -}; - -struct K : public ThrowingMoveConstructor { - K(K &&) = default; - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructors should be marked noexcept [performance-noexcept-move-constructor] - K &operator=(K &&) = default; - // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operators should be marked noexcept [performance-noexcept-move-constructor] -}; - -struct InheritFromThrowingMoveConstrcutor : public ThrowingMoveConstructor -{}; - -struct L { - L(L &&) = default; - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructors should be marked noexcept [performance-noexcept-move-constructor] - L &operator=(L &&) = default; - // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operators should be marked noexcept [performance-noexcept-move-constructor] - - InheritFromThrowingMoveConstrcutor IFF; -}; - -struct M : public InheritFromThrowingMoveConstrcutor { - M(M &&) = default; - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructors should be marked noexcept [performance-noexcept-move-constructor] - M &operator=(M &&) = default; - // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operators should be marked noexcept [performance-noexcept-move-constructor] -}; - -struct N : public IntWrapper, ThrowingMoveConstructor { - N(N &&) = default; - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructors should be marked noexcept [performance-noexcept-move-constructor] - N &operator=(N &&) = default; - // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operators should be marked noexcept [performance-noexcept-move-constructor] -}; - -struct O : virtual IntWrapper, ThrowingMoveConstructor { - O(O &&) = default; - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructors should be marked noexcept [performance-noexcept-move-constructor] - O &operator=(O &&) = default; - // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operators should be marked noexcept [performance-noexcept-move-constructor] -}; - -class OK {}; - -void f() { - OK a; - a = OK(); -} - -class OK1 { -public: - OK1(); - OK1(const OK1 &); - OK1(OK1 &&) noexcept; - OK1 &operator=(OK1 &&) noexcept; - void f(); - void g() noexcept; -}; - -struct OK2 { - static constexpr bool kTrue = true; - - OK2(OK2 &&) noexcept(true) {} - OK2 &operator=(OK2 &&) noexcept(kTrue) { return *this; } -}; - -struct OK3 { - OK3(OK3 &&) noexcept(false) {} - OK3 &operator=(OK3 &&) = delete; -}; - -struct OK4 { - OK4(OK4 &&) noexcept = default; - OK4 &operator=(OK4 &&) noexcept = default; -}; - -struct OK5 { - OK5(OK5 &&) noexcept(true) = default; - OK5 &operator=(OK5 &&) noexcept(true) = default; -}; - -struct OK6 { - OK6(OK6 &&) = default; - OK6& operator=(OK6 &&) = default; -}; - -template -struct OK7 { - OK7(OK7 &&) = default; - OK7& operator=(OK7 &&) = default; -}; - -template -struct OK8 { - OK8(OK8 &&) noexcept = default; - OK8& operator=(OK8 &&) noexcept = default; -}; - -template -struct OK9 { - OK9(OK9 &&) noexcept(true) = default; - OK9& operator=(OK9 &&) noexcept(true) = default; -}; - -template -struct OK10 { - OK10(OK10 &&) noexcept(false) = default; - OK10& operator=(OK10 &&) noexcept(false) = default; -}; - -template -struct OK11 { - OK11(OK11 &&) = delete; - OK11& operator=(OK11 &&) = delete; -}; - -void noexcept_function() noexcept {} - -struct OK12 { - OK12(OK12 &&) noexcept(noexcept(noexcept_function())); - OK12 &operator=(OK12 &&) noexcept(noexcept(noexcept_function)); -}; - -struct OK13 { - OK13(OK13 &&) noexcept(noexcept(noexcept_function)) = default; - OK13 &operator=(OK13 &&) noexcept(noexcept(noexcept_function)) = default; -}; - -template struct OK14 { - OK14(OK14 &&) noexcept(noexcept(TemplatedType::f())); - OK14 &operator=(OK14 &&) noexcept(noexcept(TemplatedType::f())); -}; - -struct OK15 { - OK15(OK15 &&) = default; - OK15 &operator=(OK15 &&) = default; - - int member; -}; - -template -struct OK16 { - OK16(OK16 &&) = default; - OK16 &operator=(OK16 &&) = default; - - int member; -}; - -struct OK17 -{ - OK17(OK17 &&) = default; - OK17 &operator=(OK17 &&) = default; - OK empty_field; -}; - -template -struct OK18 -{ - OK18(OK18 &&) = default; - OK18 &operator=(OK18 &&) = default; - - OK empty_field; -}; - -struct OK19 : public OK -{ - OK19(OK19 &&) = default; - OK19 &operator=(OK19 &&) = default; -}; - -struct OK20 : virtual OK -{ - OK20(OK20 &&) = default; - OK20 &operator=(OK20 &&) = default; -}; - -template -struct OK21 : public T -{ - OK21() = default; - OK21(OK21 &&) = default; - OK21 &operator=(OK21 &&) = default; -}; - -template -struct OK22 : virtual T -{ - OK22() = default; - OK22(OK22 &&) = default; - OK22 &operator=(OK22 &&) = default; -}; - -template -struct OK23 { - OK23()= default; - OK23(OK23 &&) = default; - OK23 &operator=(OK23 &&) = default; - - T member; -}; - -void testTemplates() { - OK21 value(OK21{}); - value = OK21{}; - - OK22 value2{OK22{}}; - value2 = OK22{}; - - OK23 value3{OK23{}}; - value3 =OK23{}; -} - -struct OK24 : public Empty, OK1 { - OK24(OK24 &&) = default; - OK24 &operator=(OK24 &&) = default; -}; - -struct OK25 : virtual Empty, OK1 { - OK25(OK25 &&) = default; - OK25 &operator=(OK25 &&) = default; -}; - -struct OK26 : public Empty, IntWrapper { - OK26(OK26 &&) = default; - OK26 &operator=(OK26 &&) = default; -}; - -template -struct OK27 : public T -{ - OK27(OK27 &&) = default; - OK27 &operator=(OK27 &&) = default; -}; - -template -struct OK28 : virtual T -{ - OK28(OK28 &&) = default; - OK28 &operator=(OK28 &&) = default; -}; - -template -struct OK29 { - OK29(OK29 &&) = default; - OK29 &operator=(OK29 &&) = default; - - T member; -}; - -struct OK30 { - OK30(OK30 &&) noexcept(TrueT::value) = default; - OK30& operator=(OK30 &&) noexcept(TrueT::value) = default; -}; - -template -struct OK31 { - OK31(OK31 &&) noexcept(TrueT::value) = default; - OK31& operator=(OK31 &&) noexcept(TrueT::value) = default; -}; diff --git a/clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-move-constructor-fix.cpp b/clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-special-functions-fix.cpp rename from clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-move-constructor-fix.cpp rename to clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-special-functions-fix.cpp --- a/clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-move-constructor-fix.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-special-functions-fix.cpp @@ -1,4 +1,4 @@ -// RUN: %check_clang_tidy %s performance-noexcept-move-constructor %t -- -- -fexceptions +// RUN: %check_clang_tidy %s performance-noexcept-special-functions %t -- -- -fexceptions struct C_1 { ~C_1() {} diff --git a/clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-special-functions.cpp b/clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-special-functions.cpp new file mode 100644 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-special-functions.cpp @@ -0,0 +1,601 @@ +// RUN: %check_clang_tidy %s performance-noexcept-special-functions %t -- -- -fexceptions + +struct Empty +{}; + +struct IntWrapper { + int value; +}; + +template +struct FalseT { + static constexpr bool value = false; +}; + +template +struct TrueT { + static constexpr bool value = true; +}; + +struct ThrowOnAnything { + ThrowOnAnything() noexcept(false); + ThrowOnAnything(ThrowOnAnything&&) noexcept(false); + ThrowOnAnything& operator=(ThrowOnAnything &&) noexcept(false); + ~ThrowOnAnything() noexcept(false); +}; + +class A { + A(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: default constructor should be marked noexcept [performance-noexcept-special-functions] + // CHECK-FIXES: A() noexcept ; + A(A &&); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructor should be marked noexcept [performance-noexcept-special-functions] + // CHECK-FIXES: A(A &&) noexcept ; + A &operator=(A &&); + // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operator should be marked noexcept [performance-noexcept-special-functions] + // CHECK-FIXES: A &operator=(A &&) noexcept ; + void swap(A &); + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: swap function should be marked noexcept [performance-noexcept-special-functions] + // CHECK-FIXES: void swap(A &) noexcept ; +}; + +void swap(A &, A &); +// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: swap function should be marked noexcept [performance-noexcept-special-functions] +// CHECK-FIXES: void swap(A &, A &) noexcept ; + +struct B { + static constexpr bool kFalse = false; + B() noexcept(kFalse); + // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: noexcept specifier on the default constructor evaluates to 'false' [performance-noexcept-special-functions] + B(B &&) noexcept(kFalse); + // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: noexcept specifier on the move constructor evaluates to 'false' [performance-noexcept-special-functions] + B &operator=(B &&) noexcept(kFalse); + // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: noexcept specifier on the move assignment operator evaluates to 'false' [performance-noexcept-special-functions] + ~B() noexcept(kFalse); + // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: noexcept specifier on the destructor evaluates to 'false' [performance-noexcept-special-functions] + void swap(B &) noexcept(kFalse); + // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: noexcept specifier on the swap function evaluates to 'false' [performance-noexcept-special-functions] +}; + +void swap(B &, B &); +// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: swap function should be marked noexcept [performance-noexcept-special-functions] +// CHECK-FIXES: void swap(B &, B &) noexcept ; + +template +struct C { + C(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: default constructor should be marked noexcept [performance-noexcept-special-functions] + // CHECK-FIXES: C() noexcept ; + C(C &&); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructor should be marked noexcept [performance-noexcept-special-functions] + // CHECK-FIXES: C(C &&) noexcept ; + C& operator=(C &&); + // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operator should be marked noexcept [performance-noexcept-special-functions] + // CHECK-FIXES: C& operator=(C &&) noexcept ; + void swap(C&); + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: swap function should be marked noexcept [performance-noexcept-special-functions] + // CHECK-FIXES: void swap(C&) noexcept ; +}; + +template +void swap(C&, C&); +// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: swap function should be marked noexcept [performance-noexcept-special-functions] +// CHECK-FIXES: void swap(C&, C&) noexcept ; +void swap(C&, C&); +// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: swap function should be marked noexcept [performance-noexcept-special-functions] +// CHECK-FIXES: void swap(C&, C&) noexcept ; + +struct D { + static constexpr bool kFalse = false; + D() noexcept(kFalse) = default; + // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: noexcept specifier on the default constructor evaluates to 'false' [performance-noexcept-special-functions] + D(D &&) noexcept(kFalse) = default; + // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: noexcept specifier on the move constructor evaluates to 'false' [performance-noexcept-special-functions] + D& operator=(D &&) noexcept(kFalse) = default; + // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: noexcept specifier on the move assignment operator evaluates to 'false' [performance-noexcept-special-functions] + ~D() noexcept(kFalse) = default; + // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: noexcept specifier on the destructor evaluates to 'false' [performance-noexcept-special-functions] +}; + +template +struct E { + static constexpr bool kFalse = false; + E() noexcept(kFalse); + // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: noexcept specifier on the default constructor evaluates to 'false' [performance-noexcept-special-functions] + E(E &&) noexcept(kFalse); + // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: noexcept specifier on the move constructor evaluates to 'false' [performance-noexcept-special-functions] + E& operator=(E &&) noexcept(kFalse); + // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: noexcept specifier on the move assignment operator evaluates to 'false' + ~E() noexcept(kFalse); + // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: noexcept specifier on the destructor evaluates to 'false' + void swap(E &) noexcept(kFalse); + // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: noexcept specifier on the swap function evaluates to 'false' [performance-noexcept-special-functions] +}; + +template +void swap(E &, E &) noexcept(E::kFalse); +// CHECK-MESSAGES: :[[@LINE-1]]:36: warning: noexcept specifier on the swap function evaluates to 'false' [performance-noexcept-special-functions] +void swap(E &, E &) noexcept(E::kFalse); +// CHECK-MESSAGES: :[[@LINE-1]]:40: warning: noexcept specifier on the swap function evaluates to 'false' [performance-noexcept-special-functions] + +template +struct F { + static constexpr bool kFalse = false; + F() noexcept(kFalse) = default; + // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: noexcept specifier on the default constructor evaluates to 'false' [performance-noexcept-special-functions] + F(F &&) noexcept(kFalse) = default; + // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: noexcept specifier on the move constructor evaluates to 'false' [performance-noexcept-special-functions] + F& operator=(F &&) noexcept(kFalse) = default; + // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: noexcept specifier on the move assignment operator evaluates to 'false' [performance-noexcept-special-functions] + ~F() noexcept(kFalse) = default; + // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: noexcept specifier on the destructor evaluates to 'false' [performance-noexcept-special-functions] +}; + +struct G { + G() = default; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: default constructor should be marked noexcept [performance-noexcept-special-functions] + // CHECK-FIXES: G() noexcept = default; + G(G &&) = default; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructor should be marked noexcept [performance-noexcept-special-functions] + // CHECK-FIXES: G(G &&) noexcept = default; + G& operator=(G &&) = default; + // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operator should be marked noexcept [performance-noexcept-special-functions] + // CHECK-FIXES: G& operator=(G &&) noexcept = default; + ~G() = default; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: destructor should be marked noexcept [performance-noexcept-special-functions] + // CHECK-FIXES: ~G() noexcept = default; + + ThrowOnAnything field; +}; + +void throwing_function() noexcept(false) {} + +struct H { + H() noexcept(noexcept(throwing_function())); + // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: noexcept specifier on the default constructor evaluates to 'false' [performance-noexcept-special-functions] + H(H &&) noexcept(noexcept(throwing_function())); + // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: noexcept specifier on the move constructor evaluates to 'false' [performance-noexcept-special-functions] + H &operator=(H &&) noexcept(noexcept(throwing_function())); + // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: noexcept specifier on the move assignment operator evaluates to 'false' [performance-noexcept-special-functions] + ~H() noexcept(noexcept(throwing_function())); + // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: noexcept specifier on the destructor evaluates to 'false' [performance-noexcept-special-functions] + void swap(H &) noexcept(noexcept(throwing_function())); + // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: noexcept specifier on the swap function evaluates to 'false' [performance-noexcept-special-functions] +}; + +void swap(H &, H &) noexcept(noexcept(throwing_function())); +// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: noexcept specifier on the swap function evaluates to 'false' [performance-noexcept-special-functions] + +template +struct I { + I() noexcept(noexcept(throwing_function())); + // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: noexcept specifier on the default constructor evaluates to 'false' [performance-noexcept-special-functions] + I(I &&) noexcept(noexcept(throwing_function())); + // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: noexcept specifier on the move constructor evaluates to 'false' [performance-noexcept-special-functions] + I &operator=(I &&) noexcept(noexcept(throwing_function())); + // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: noexcept specifier on the move assignment operator evaluates to 'false' [performance-noexcept-special-functions] + ~I() noexcept(noexcept(throwing_function())); + // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: noexcept specifier on the destructor evaluates to 'false' [performance-noexcept-special-functions] + void swap(I &) noexcept(noexcept(throwing_function())); + // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: noexcept specifier on the swap function evaluates to 'false' [performance-noexcept-special-functions] +}; + +template +void swap(I &, I &) noexcept(noexcept(throwing_function())); +// CHECK-MESSAGES: :[[@LINE-1]]:36: warning: noexcept specifier on the swap function evaluates to 'false' [performance-noexcept-special-functions] +void swap(I &, I &) noexcept(noexcept(throwing_function())); +// CHECK-MESSAGES: :[[@LINE-1]]:40: warning: noexcept specifier on the swap function evaluates to 'false' [performance-noexcept-special-functions] + +template struct TemplatedType { + static void f() {} +}; + +template <> struct TemplatedType { + static void f() noexcept {} +}; + +struct J { + J() noexcept(noexcept(TemplatedType::f())); + // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: noexcept specifier on the default constructor evaluates to 'false' [performance-noexcept-special-functions] + J(J &&) noexcept(noexcept(TemplatedType::f())); + // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: noexcept specifier on the move constructor evaluates to 'false' [performance-noexcept-special-functions] + J &operator=(J &&) noexcept(noexcept(TemplatedType::f())); + // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: noexcept specifier on the move assignment operator evaluates to 'false' [performance-noexcept-special-functions] + ~J() noexcept(noexcept(TemplatedType::f())); + // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: noexcept specifier on the destructor evaluates to 'false' [performance-noexcept-special-functions] + void swap(J &) noexcept(noexcept(TemplatedType::f())); + // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: noexcept specifier on the swap function evaluates to 'false' [performance-noexcept-special-functions] +}; + +void swap(J &, J &) noexcept(noexcept(TemplatedType::f())); +// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: noexcept specifier on the swap function evaluates to 'false' [performance-noexcept-special-functions] + +struct K : public ThrowOnAnything { + K() = default; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: default constructor should be marked noexcept [performance-noexcept-special-functions] + // CHECK-FIXES: K() noexcept = default; + K(K &&) = default; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructor should be marked noexcept [performance-noexcept-special-functions] + // CHECK-FIXES: K(K &&) noexcept = default; + K &operator=(K &&) = default; + // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operator should be marked noexcept [performance-noexcept-special-functions] + // CHECK-FIXES: K &operator=(K &&) noexcept = default; + ~K() = default; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: destructor should be marked noexcept [performance-noexcept-special-functions] + // CHECK-FIXES: ~K() noexcept = default; +}; + +struct InheritFromThrowOnAnything : public ThrowOnAnything +{}; + +struct L { + L() = default; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: default constructor should be marked noexcept [performance-noexcept-special-functions] + // CHECK-FIXES: L() noexcept = default; + L(L &&) = default; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructor should be marked noexcept [performance-noexcept-special-functions] + // CHECK-FIXES: L(L &&) noexcept = default; + L &operator=(L &&) = default; + // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operator should be marked noexcept [performance-noexcept-special-functions] + // CHECK-FIXES: L &operator=(L &&) noexcept = default; + ~L() = default; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: destructor should be marked noexcept [performance-noexcept-special-functions] + // CHECK-FIXES: ~L() noexcept = default; + + InheritFromThrowOnAnything IFF; +}; + +struct M : public InheritFromThrowOnAnything { + M() = default; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: default constructor should be marked noexcept [performance-noexcept-special-functions] + // CHECK-FIXES: M() noexcept = default; + M(M &&) = default; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructor should be marked noexcept [performance-noexcept-special-functions] + // CHECK-FIXES: M(M &&) noexcept = default; + M &operator=(M &&) = default; + // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operator should be marked noexcept [performance-noexcept-special-functions] + // CHECK-FIXES: M &operator=(M &&) noexcept = default; + ~M() = default; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: destructor should be marked noexcept [performance-noexcept-special-functions] + // CHECK-FIXES: ~M() noexcept = default; +}; + +struct N : public IntWrapper, ThrowOnAnything { + N() = default; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: default constructor should be marked noexcept [performance-noexcept-special-functions] + // CHECK-FIXES: N() noexcept = default; + N(N &&) = default; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructor should be marked noexcept [performance-noexcept-special-functions] + // CHECK-FIXES: N(N &&) noexcept = default; + N &operator=(N &&) = default; + // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operator should be marked noexcept [performance-noexcept-special-functions] + // CHECK-FIXES: N &operator=(N &&) noexcept = default; + ~N() = default; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: destructor should be marked noexcept [performance-noexcept-special-functions] + // CHECK-FIXES: ~N() noexcept = default; +}; + +struct O : virtual IntWrapper, ThrowOnAnything { + O() = default; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: default constructor should be marked noexcept [performance-noexcept-special-functions] + // CHECK-FIXES: O() noexcept = default; + O(O &&) = default; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructor should be marked noexcept [performance-noexcept-special-functions] + // CHECK-FIXES: O(O &&) noexcept = default; + O &operator=(O &&) = default; + // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operator should be marked noexcept [performance-noexcept-special-functions] + // CHECK-FIXES: O &operator=(O &&) noexcept = default; + ~O() = default; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: destructor should be marked noexcept [performance-noexcept-special-functions] + // CHECK-FIXES: ~O() noexcept = default; +}; + +class OK {}; + +void f() { + OK a; + a = OK(); +} + +struct OK1 { + OK1() noexcept; + OK1(const OK1 &); + OK1(OK1 &&) noexcept; + OK1 &operator=(OK1 &&) noexcept; + ~OK1() noexcept; + void f(); + void g() noexcept; + void swap(OK1 &) noexcept; +}; + +void swap(OK1 &, OK1 &) noexcept; + +struct OK2 { + static constexpr bool kTrue = true; + + OK2() noexcept(true) {} + OK2(OK2 &&) noexcept(true) {} + OK2 &operator=(OK2 &&) noexcept(kTrue) { return *this; } + ~OK2() noexcept(true) {} + void swap(OK2 &) noexcept(kTrue) {} +}; + +void swap(OK2 &, OK2 &) = delete; + +struct OK3 { + OK3() = delete; + OK3(OK3 &&) noexcept(false) {} + OK3 &operator=(OK3 &&) = delete; + ~OK3() noexcept(false) {} + void swap(OK3 &) noexcept(false) {} +}; + +void swap(OK3 &, OK3 &)noexcept(false) {} + +struct OK4 { + OK4() = default; + OK4(OK4 &&) noexcept = default; + OK4 &operator=(OK4 &&) noexcept = default; + ~OK4() = default; +}; + +struct OK5 { + OK5() noexcept(true) = default; + OK5(OK5 &&) noexcept(true) = default; + OK5 &operator=(OK5 &&) noexcept(true) = default; + ~OK5() noexcept(true) = default; +}; + +struct OK6 { + OK6() = default; + OK6(OK6 &&) = default; + OK6& operator=(OK6 &&) = default; + ~OK6() = default; +}; + +template +struct OK7 { + OK7() = default; + OK7(OK7 &&) = default; + OK7& operator=(OK7 &&) = default; + ~OK7() = default; +}; + +template +struct OK8 { + OK8() noexcept = default; + OK8(OK8 &&) noexcept = default; + OK8& operator=(OK8 &&) noexcept = default; + ~OK8() noexcept = default; +}; + +template +struct OK9 { + OK9() noexcept(true) = default; + OK9(OK9 &&) noexcept(true) = default; + OK9& operator=(OK9 &&) noexcept(true) = default; + ~OK9() noexcept(true) = default; +}; + +template +struct OK10 { + OK10() noexcept(false) = default; + OK10(OK10 &&) noexcept(false) = default; + OK10& operator=(OK10 &&) noexcept(false) = default; + ~OK10() noexcept(false) = default; +}; + +template +struct OK11 { + OK11() = delete; + OK11(OK11 &&) = delete; + OK11& operator=(OK11 &&) = delete; + ~OK11() = delete; +}; + +void noexcept_function() noexcept {} + +struct OK12 { + OK12() noexcept(noexcept(noexcept_function())); + OK12(OK12 &&) noexcept(noexcept(noexcept_function())); + OK12 &operator=(OK12 &&) noexcept(noexcept(noexcept_function)); + ~OK12() noexcept(noexcept(noexcept_function())); + void swap(OK12 &) noexcept(noexcept(noexcept_function())); +}; + +void swap(OK12 &, OK12 &) noexcept(noexcept(noexcept_function())) {} + +struct OK13 { + OK13() noexcept(noexcept(noexcept_function())) = default; + OK13(OK13 &&) noexcept(noexcept(noexcept_function)) = default; + OK13 &operator=(OK13 &&) noexcept(noexcept(noexcept_function)) = default; + ~OK13() noexcept(noexcept(noexcept_function())) = default; +}; + +template +struct OK14 { + OK14() noexcept(noexcept(TemplatedType::f())); + OK14(OK14 &&) noexcept(noexcept(TemplatedType::f())); + OK14 &operator=(OK14 &&) noexcept(noexcept(TemplatedType::f())); + ~OK14() noexcept(noexcept(TemplatedType::f())); + void swap(OK14 &) noexcept(noexcept(TemplatedType::f())); +}; + +template +void swap(OK14 &, OK14 &) noexcept(noexcept(TemplatedType::f())); +void swap(OK14 &, OK14 &) noexcept(noexcept(TemplatedType::f())); + +struct OK15 { + OK15() = default; + OK15(OK15 &&) = default; + OK15 &operator=(OK15 &&) = default; + ~OK15() = default; + + int member; +}; + +template +struct OK16 { + OK16() = default; + OK16(OK16 &&) = default; + OK16 &operator=(OK16 &&) = default; + ~OK16() = default; + + int member; +}; + +struct OK17 +{ + OK17() = default; + OK17(OK17 &&) = default; + OK17 &operator=(OK17 &&) = default; + ~OK17() = default; + + OK empty_field; +}; + +template +struct OK18 +{ + OK18() = default; + OK18(OK18 &&) = default; + OK18 &operator=(OK18 &&) = default; + ~OK18() = default; + + OK empty_field; +}; + +struct OK19 : public OK +{ + OK19() = default; + OK19(OK19 &&) = default; + OK19 &operator=(OK19 &&) = default; + ~OK19() = default; +}; + +struct OK20 : virtual OK +{ + OK20() = default; + OK20(OK20 &&) = default; + OK20 &operator=(OK20 &&) = default; + ~OK20() = default; +}; + +template +struct OK21 : public T +{ + OK21() = default; + OK21(OK21 &&) = default; + OK21 &operator=(OK21 &&) = default; + ~OK21() = default; +}; + +template +struct OK22 : virtual T +{ + OK22() = default; + OK22(OK22 &&) = default; + OK22 &operator=(OK22 &&) = default; + ~OK22() = default; +}; + +template +struct OK23 { + OK23()= default; + OK23(OK23 &&) = default; + OK23 &operator=(OK23 &&) = default; + ~OK23() = default; + + T member; +}; + +void testTemplates() { + OK21 value(OK21{}); + value = OK21{}; + + OK22 value2{OK22{}}; + value2 = OK22{}; + + OK23 value3{OK23{}}; + value3 =OK23{}; +} + +struct OK24 : public Empty, OK1 { + OK24() = default; + OK24(OK24 &&) = default; + OK24 &operator=(OK24 &&) = default; + ~OK24() = default; +}; + +struct OK25 : virtual Empty, OK1 { + OK25() = default; + OK25(OK25 &&) = default; + OK25 &operator=(OK25 &&) = default; + ~OK25() = default; +}; + +struct OK26 : public Empty, IntWrapper { + OK26() = default; + OK26(OK26 &&) = default; + OK26 &operator=(OK26 &&) = default; + ~OK26() = default; +}; + +template +struct OK27 : public T { + OK27() = default; + OK27(OK27 &&) = default; + OK27 &operator=(OK27 &&) = default; + ~OK27() = default; +}; + +template +struct OK28 : virtual T { + OK28() = default; + OK28(OK28 &&) = default; + OK28 &operator=(OK28 &&) = default; + ~OK28() = default; +}; + +template +struct OK29 { + OK29() = default; + OK29(OK29 &&) = default; + OK29 &operator=(OK29 &&) = default; + ~OK29() = default; + + T member; +}; + +struct OK30 { + OK30() noexcept(TrueT::value) = default; + OK30(OK30 &&) noexcept(TrueT::value) = default; + OK30& operator=(OK30 &&) noexcept(TrueT::value) = default; + ~OK30() noexcept(TrueT::value) = default; +}; + +template +struct OK31 { + OK31() noexcept(TrueT::value) = default; + OK31(OK31 &&) noexcept(TrueT::value) = default; + OK31& operator=(OK31 &&) noexcept(TrueT::value) = default; + ~OK31() noexcept(TrueT::value) = default; +}; + +struct OK32 { + ~OK32(); +}; + +template +struct OK33 { + ~OK33(); +}; + +struct OK34 { + ~OK34() {} +}; + +template +struct OK35 { + ~OK35() {} +};