Skip to content

Commit

Permalink
Add a clang-tidy check for move constructors/assignment ops without n…
Browse files Browse the repository at this point in the history
…oexcept.

Summary:
Add a clang-tidy check (misc-noexcept-move-ctors) for move constructors
and assignment operators not using noexcept.

http://llvm.org/PR23519

Reviewers: klimek

Reviewed By: klimek

Subscribers: curdeius, cfe-commits

Differential Revision: http://reviews.llvm.org/D9933

llvm-svn: 238013
  • Loading branch information
alexfh committed May 22, 2015
1 parent 73dc2e4 commit 3396a8b
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 0 deletions.
1 change: 1 addition & 0 deletions clang-tools-extra/clang-tidy/misc/CMakeLists.txt
Expand Up @@ -8,6 +8,7 @@ add_clang_library(clangTidyMiscModule
InaccurateEraseCheck.cpp
InefficientAlgorithmCheck.cpp
MiscTidyModule.cpp
NoexceptMoveCtorsCheck.cpp
StaticAssertCheck.cpp
SwappedArgumentsCheck.cpp
UndelegatedConstructor.cpp
Expand Down
3 changes: 3 additions & 0 deletions clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp
Expand Up @@ -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"
Expand All @@ -41,6 +42,8 @@ class MiscModule : public ClangTidyModule {
"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>(
Expand Down
65 changes: 65 additions & 0 deletions 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

37 changes: 37 additions & 0 deletions 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

37 changes: 37 additions & 0 deletions 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) {}
};

0 comments on commit 3396a8b

Please sign in to comment.