summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang-tools-extra/clang-tidy/misc/CMakeLists.txt1
-rw-r--r--clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp3
-rw-r--r--clang-tools-extra/clang-tidy/misc/NoexceptMoveCtorsCheck.cpp65
-rw-r--r--clang-tools-extra/clang-tidy/misc/NoexceptMoveCtorsCheck.h37
-rw-r--r--clang-tools-extra/test/clang-tidy/misc-noexcept-move-ctors.cpp37
5 files changed, 143 insertions, 0 deletions
diff --git a/clang-tools-extra/clang-tidy/misc/CMakeLists.txt b/clang-tools-extra/clang-tidy/misc/CMakeLists.txt
index 42b711f5580..ca7250a8a42 100644
--- a/clang-tools-extra/clang-tidy/misc/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/misc/CMakeLists.txt
@@ -8,6 +8,7 @@ add_clang_library(clangTidyMiscModule
InaccurateEraseCheck.cpp
InefficientAlgorithmCheck.cpp
MiscTidyModule.cpp
+ NoexceptMoveCtorsCheck.cpp
StaticAssertCheck.cpp
SwappedArgumentsCheck.cpp
UndelegatedConstructor.cpp
diff --git a/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp b/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp
index 76585e05681..36e6d401a61 100644
--- a/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp
@@ -16,6 +16,7 @@
#include "BoolPointerImplicitConversionCheck.h"
#include "InaccurateEraseCheck.h"
#include "InefficientAlgorithmCheck.h"
+#include "NoexceptMoveCtorsCheck.h"
#include "StaticAssertCheck.h"
#include "SwappedArgumentsCheck.h"
#include "UndelegatedConstructor.h"
@@ -41,6 +42,8 @@ public:
"misc-inaccurate-erase");
CheckFactories.registerCheck<InefficientAlgorithmCheck>(
"misc-inefficient-algorithm");
+ CheckFactories.registerCheck<NoexceptMoveCtorsCheck>(
+ "misc-noexcept-move-ctors");
CheckFactories.registerCheck<StaticAssertCheck>(
"misc-static-assert");
CheckFactories.registerCheck<SwappedArgumentsCheck>(
diff --git a/clang-tools-extra/clang-tidy/misc/NoexceptMoveCtorsCheck.cpp b/clang-tools-extra/clang-tidy/misc/NoexceptMoveCtorsCheck.cpp
new file mode 100644
index 00000000000..3b74b8a2ae5
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/misc/NoexceptMoveCtorsCheck.cpp
@@ -0,0 +1,65 @@
+//===--- NoexceptMoveCtorsCheck.cpp - clang-tidy---------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "NoexceptMoveCtorsCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+
+void NoexceptMoveCtorsCheck::registerMatchers(MatchFinder *Finder) {
+ Finder->addMatcher(
+ methodDecl(anyOf(constructorDecl(), hasOverloadedOperatorName("=")))
+ .bind("decl"),
+ this);
+}
+
+void NoexceptMoveCtorsCheck::check(const MatchFinder::MatchResult &Result) {
+ if (const auto *Decl = Result.Nodes.getNodeAs<CXXMethodDecl>("decl")) {
+ StringRef MethodType = "assignment operator";
+ if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(Decl)) {
+ if (!Ctor->isMoveConstructor())
+ return;
+ MethodType = "constructor";
+ } else if (!Decl->isMoveAssignmentOperator()) {
+ return;
+ }
+
+ const auto *ProtoType = Decl->getType()->getAs<FunctionProtoType>();
+ switch(ProtoType->getNoexceptSpec(*Result.Context)) {
+ case FunctionProtoType::NR_NoNoexcept:
+ diag(Decl->getLocation(), "move %0s should be marked noexcept")
+ << MethodType;
+ // FIXME: Add a fixit.
+ break;
+ case FunctionProtoType::NR_Throw:
+ // Don't complain about nothrow(false), but complain on nothrow(expr)
+ // where expr evaluates to false.
+ if (const Expr *E = ProtoType->getNoexceptExpr()) {
+ if (isa<CXXBoolLiteralExpr>(E))
+ break;
+ diag(E->getExprLoc(),
+ "noexcept specifier on the move %0 evaluates to 'false'")
+ << MethodType;
+ }
+ break;
+ case FunctionProtoType::NR_Nothrow:
+ case FunctionProtoType::NR_Dependent:
+ case FunctionProtoType::NR_BadNoexcept:
+ break;
+ }
+ }
+}
+
+} // namespace tidy
+} // namespace clang
+
diff --git a/clang-tools-extra/clang-tidy/misc/NoexceptMoveCtorsCheck.h b/clang-tools-extra/clang-tidy/misc/NoexceptMoveCtorsCheck.h
new file mode 100644
index 00000000000..3e5b0bb05b7
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/misc/NoexceptMoveCtorsCheck.h
@@ -0,0 +1,37 @@
+//===--- NoexceptMoveCtorsCheck.h - clang-tidy-------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_NOEXCEPT_MOVE_CTORS_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_NOEXCEPT_MOVE_CTORS_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+
+/// \brief The check flags move constructors and assignment operators not marked
+/// with \c noexcept or marked with \c noexcept(expr) where \c expr evaluates to
+/// \c false (but is not a \c false literal itself).
+///
+/// Move constructors of all the types used with STL containers, for example,
+/// need to be declared \c noexcept. Otherwise STL will choose copy constructors
+/// instead. The same is valid for move assignment operations.
+class NoexceptMoveCtorsCheck : public ClangTidyCheck {
+public:
+ NoexceptMoveCtorsCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_NOEXCEPT_MOVE_CTORS_H
+
diff --git a/clang-tools-extra/test/clang-tidy/misc-noexcept-move-ctors.cpp b/clang-tools-extra/test/clang-tidy/misc-noexcept-move-ctors.cpp
new file mode 100644
index 00000000000..b4be26ff656
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/misc-noexcept-move-ctors.cpp
@@ -0,0 +1,37 @@
+// RUN: $(dirname %s)/check_clang_tidy.sh %s misc-noexcept-move-ctors %t
+// REQUIRES: shell
+
+class A {
+ A(A &&);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructors should be marked noexcept [misc-noexcept-move-ctors]
+ A &operator=(A &&);
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operators should
+};
+
+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' [misc-noexcept-move-ctors]
+};
+
+class OK1 {
+ public:
+ OK1();
+ OK1(const OK1 &);
+ OK1(OK1&&) noexcept;
+ OK1 &operator=(OK1 &&) noexcept;
+ void f();
+ void g() noexcept;
+};
+
+class OK2 {
+ static constexpr bool kTrue = true;
+
+public:
+ OK2(OK2 &&) noexcept(true) {}
+ OK2 &operator=(OK2 &&) noexcept(kTrue) { return *this; }
+};
+
+struct OK3 {
+ OK3(OK3 &&) noexcept(false) {}
+};
OpenPOWER on IntegriCloud