aaron.ballman updated this revision to Diff 40064.
aaron.ballman added a comment.
Added new test cases
http://reviews.llvm.org/D14619
Files:
clang-tidy/cert/CERTTidyModule.cpp
clang-tidy/cert/CMakeLists.txt
clang-tidy/cert/ThrownExceptionTypeCheck.cpp
clang-tidy/cert/ThrownExceptionTypeCheck.h
docs/clang-tidy/checks/cert-thrown-exception-type.rst
docs/clang-tidy/checks/list.rst
test/clang-tidy/cert-throw-exception-type.cpp
Index: test/clang-tidy/cert-throw-exception-type.cpp
===================================================================
--- test/clang-tidy/cert-throw-exception-type.cpp
+++ test/clang-tidy/cert-throw-exception-type.cpp
@@ -0,0 +1,112 @@
+// RUN: %check_clang_tidy %s cert-err60-cpp %t -- -- -std=c++11 -fcxx-exceptions
+
+struct S {};
+struct T : S {};
+struct U {
+ U() = default;
+ U(const U&) = default;
+};
+
+struct V {
+ V() = default;
+ V(const V&) noexcept;
+};
+
+struct W {
+ W() = default;
+ W(const W&) noexcept(false);
+};
+
+struct X {
+ X() = default;
+ X(const X&) {}
+};
+
+struct Y {
+ Y() = default;
+ Y(const Y&) throw();
+};
+
+struct Z {
+ Z() = default;
+ Z(const Z&) throw(int);
+};
+
+void g() noexcept(false);
+
+struct A {
+ A() = default;
+ A(const A&) noexcept(noexcept(g()));
+};
+
+struct B {
+ B() = default;
+ B(const B&) = default;
+ B(const A&) noexcept(false);
+};
+
+class C {
+ W M; // W is not no-throw copy constructible
+public:
+ C() = default;
+ C(const C&) = default;
+};
+
+struct D {
+ D() = default;
+ D(const D&) noexcept(false);
+ D(D&) noexcept(true);
+};
+
+struct E {
+ E() = default;
+ E(E&) noexcept(true);
+ E(const E&) noexcept(false);
+};
+
+struct Allocates {
+ int *x;
+ Allocates() : x(new int(0)) {}
+ Allocates(const Allocates &other) : x(new int(*other.x)) {}
+};
+
+struct OptionallyAllocates {
+ int *x;
+ OptionallyAllocates() : x(new int(0)) {}
+ OptionallyAllocates(const Allocates &other) noexcept(true) {
+ try {
+ x = new int(*other.x);
+ } catch (...) {
+ x = nullptr;
+ }
+ }
+};
+
+void f() {
+ throw 12; // ok
+ throw "test"; // ok
+ throw S(); // ok
+ throw T(); // ok
+ throw U(); // ok
+ throw V(); // ok
+ throw W(); // match, noexcept(false)
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: thrown exception type is not nothrow copy constructible [cert-err60-cpp]
+ throw X(); // match, no noexcept clause, nontrivial
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: thrown exception type is not nothrow copy constructible
+ throw Y(); // ok
+ throw Z(); // match, throw(int)
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: thrown exception type is not nothrow copy constructible
+ throw A(); // match, noexcept(false)
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: thrown exception type is not nothrow copy constructible
+ throw B(); // ok
+ throw C(); // match, C has a member variable that makes it throwing on copy
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: thrown exception type is not nothrow copy constructible
+ throw D(); // match, has throwing copy constructor
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: thrown exception type is not nothrow copy constructible
+ throw E(); // match, has throwing copy constructor
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: thrown exception type is not nothrow copy constructible
+ throw Allocates(); // match, copy constructor throws
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: thrown exception type is not nothrow copy constructible
+ throw OptionallyAllocates(); // ok
+
+}
Index: docs/clang-tidy/checks/list.rst
===================================================================
--- docs/clang-tidy/checks/list.rst
+++ docs/clang-tidy/checks/list.rst
@@ -3,6 +3,7 @@
.. toctree::
cert-setlongjmp
+ cert-thrown-exception-type
cert-variadic-function-def
cppcoreguidelines-pro-bounds-array-to-pointer-decay
cppcoreguidelines-pro-bounds-pointer-arithmetic
Index: docs/clang-tidy/checks/cert-thrown-exception-type.rst
===================================================================
--- docs/clang-tidy/checks/cert-thrown-exception-type.rst
+++ docs/clang-tidy/checks/cert-thrown-exception-type.rst
@@ -0,0 +1,9 @@
+cert-err60-cpp
+==============
+
+This check flags all throw expressions where the exception object is not nothrow
+copy constructible.
+
+This check corresponds to the CERT C++ Coding Standard rule
+`ERR60-CPP. Exception objects must be nothrow copy constructible
+<https://www.securecoding.cert.org/confluence/display/cplusplus/ERR60-CPP.+Exception+objects+must+be+nothrow+copy+constructible>`_.
Index: clang-tidy/cert/ThrownExceptionTypeCheck.h
===================================================================
--- clang-tidy/cert/ThrownExceptionTypeCheck.h
+++ clang-tidy/cert/ThrownExceptionTypeCheck.h
@@ -0,0 +1,34 @@
+//===--- ThrownExceptionTypeCheck.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_CERT_THROWNEXCEPTIONTYPECHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_THROWNEXCEPTIONTYPECHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+
+/// Checks whether a thrown object is nothrow copy constructible.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/cert-thrown-exception-type.html
+class ThrownExceptionTypeCheck : public ClangTidyCheck {
+public:
+ ThrownExceptionTypeCheck(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_CERT_THROWNEXCEPTIONTYPECHECK_H
+
Index: clang-tidy/cert/ThrownExceptionTypeCheck.cpp
===================================================================
--- clang-tidy/cert/ThrownExceptionTypeCheck.cpp
+++ clang-tidy/cert/ThrownExceptionTypeCheck.cpp
@@ -0,0 +1,62 @@
+//===--- ThrownExceptionTypeCheck.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 "ThrownExceptionTypeCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+
+void ThrownExceptionTypeCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ Finder->addMatcher(
+ cxxThrowExpr(
+ has(expr(hasType(cxxRecordDecl().bind("record"))).bind("expr"))),
+ this);
+}
+
+void ThrownExceptionTypeCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *RD = Result.Nodes.getNodeAs<CXXRecordDecl>("record");
+
+ if (!RD->hasNonTrivialCopyConstructor())
+ return;
+
+ bool Diag = false;
+ for (const auto *Ctor : RD->ctors()) {
+ if (Ctor->isCopyConstructor()) {
+ if (const auto *FnTy = Ctor->getType()->getAs<FunctionProtoType>()) {
+ Diag = !FnTy->isNothrow(*Result.Context);
+ // If any of the copy constructors is throwing, we will assume that it
+ // is plausible that the constructor may be selected by the throw and
+ // diagnose. TODO: we could work a lot harder to only consider the
+ // copy constructor selected by the throw expression and diagnose only
+ // if that one is nonthrowing. However, the FP rate from this is likely
+ // to be quite low.
+ if (Diag)
+ break;
+ }
+ }
+ }
+
+ if (!Diag)
+ return;
+
+ const auto *E = Result.Nodes.getNodeAs<Expr>("expr");
+ diag(E->getExprLoc(),
+ "thrown exception type is not nothrow copy constructible");
+}
+
+} // namespace tidy
+} // namespace clang
+
Index: clang-tidy/cert/CMakeLists.txt
===================================================================
--- clang-tidy/cert/CMakeLists.txt
+++ clang-tidy/cert/CMakeLists.txt
@@ -3,6 +3,7 @@
add_clang_library(clangTidyCERTModule
CERTTidyModule.cpp
SetLongJmpCheck.cpp
+ ThrownExceptionTypeCheck.cpp
VariadicFunctionDefCheck.cpp
LINK_LIBS
Index: clang-tidy/cert/CERTTidyModule.cpp
===================================================================
--- clang-tidy/cert/CERTTidyModule.cpp
+++ clang-tidy/cert/CERTTidyModule.cpp
@@ -17,6 +17,7 @@
#include "../misc/StaticAssertCheck.h"
#include "../misc/ThrowByValueCatchByReferenceCheck.h"
#include "SetLongJmpCheck.h"
+#include "ThrownExceptionTypeCheck.h"
#include "VariadicFunctionDefCheck.h"
namespace clang {
@@ -40,6 +41,8 @@
// ERR
CheckFactories.registerCheck<SetLongJmpCheck>(
"cert-err52-cpp");
+ CheckFactories.registerCheck<ThrownExceptionTypeCheck>(
+ "cert-err60-cpp");
CheckFactories.registerCheck<ThrowByValueCatchByReferenceCheck>(
"cert-err61-cpp");
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits