Index: clang-tidy/cert/StaticObjectExceptionCheck.cpp =================================================================== --- clang-tidy/cert/StaticObjectExceptionCheck.cpp +++ clang-tidy/cert/StaticObjectExceptionCheck.cpp @@ -22,27 +22,31 @@ if (!getLangOpts().CPlusPlus) return; - // Match any static or thread_local variable declaration that is initialized - // with a constructor that can throw. + // Match any static or thread_local variable declaration that has an + // initializer that can throw. Finder->addMatcher( varDecl(anyOf(hasThreadStorageDuration(), hasStaticStorageDuration()), unless(hasAncestor(functionDecl())), - hasInitializer(ignoringImplicit(cxxConstructExpr(hasDeclaration( - cxxConstructorDecl(unless(isNoThrow())).bind("ctor")))))) + anyOf(hasDescendant(cxxConstructExpr(hasDeclaration( + cxxConstructorDecl(unless(isNoThrow())).bind("func")))), + hasDescendant(callExpr(hasDeclaration( + functionDecl(unless(isNoThrow())).bind("func")))))) .bind("var"), this); } void StaticObjectExceptionCheck::check(const MatchFinder::MatchResult &Result) { const auto *VD = Result.Nodes.getNodeAs("var"); - const auto *Ctor = Result.Nodes.getNodeAs("ctor"); + const auto *Func = Result.Nodes.getNodeAs("func"); diag(VD->getLocation(), - "construction of %0 with %select{static|thread_local}1 storage " + "initialization of %0 with %select{static|thread_local}1 storage " "duration may throw an exception that cannot be caught") << VD << (VD->getStorageDuration() == SD_Static ? 0 : 1); - diag(Ctor->getLocation(), "possibly throwing constructor declared here", - DiagnosticIDs::Note); + diag(Func->getLocation(), + "possibly throwing %select{constructor|function}0 declared here", + DiagnosticIDs::Note) + << (isa(Func) ? 0 : 1); } } // namespace cert Index: docs/clang-tidy/checks/cert-err58-cpp.rst =================================================================== --- docs/clang-tidy/checks/cert-err58-cpp.rst +++ docs/clang-tidy/checks/cert-err58-cpp.rst @@ -4,8 +4,8 @@ ============== This check flags all ``static`` or ``thread_local`` variable declarations where -the constructor for the object may throw an exception. +the initializer for the object may throw an exception. This check corresponds to the CERT C++ Coding Standard rule -`ERR58-CPP. Constructors of objects with static or thread storage duration must not throw exceptions -`_. +`ERR58-CPP. Handle all exceptions thrown before main() begins executing +`_. Index: test/clang-tidy/cert-static-object-exception.cpp =================================================================== --- test/clang-tidy/cert-static-object-exception.cpp +++ test/clang-tidy/cert-static-object-exception.cpp @@ -16,8 +16,7 @@ explicit V(const char *) {} // Can throw }; -struct Cleanup -{ +struct Cleanup { ~Cleanup() {} }; @@ -25,30 +24,79 @@ W(Cleanup c = {}) noexcept(false); }; +struct X { + X(S = {}) noexcept; +}; + +struct Y { + S s; +}; + +struct Z { + T t; +}; + +int f(); +int g() noexcept(false); +int h() noexcept(true); + +struct UserConv_Bad { + operator int() noexcept(false); +}; + +struct UserConv_Good { + operator int() noexcept; +}; + +UserConv_Bad some_bad_func() noexcept; +UserConv_Good some_good_func() noexcept; S s; -// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: construction of 's' with static storage duration may throw an exception that cannot be caught [cert-err58-cpp] +// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: initialization of 's' with static storage duration may throw an exception that cannot be caught [cert-err58-cpp] // CHECK-MESSAGES: 4:3: note: possibly throwing constructor declared here T t; // ok U u; -// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: construction of 'u' with static storage duration may throw an exception that cannot be caught +// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: initialization of 'u' with static storage duration may throw an exception that cannot be caught // CHECK-MESSAGES: 12:3: note: possibly throwing constructor declared here V v("v"); -// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: construction of 'v' with static storage duration may throw an exception that cannot be caught +// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: initialization of 'v' with static storage duration may throw an exception that cannot be caught // CHECK-MESSAGES: 16:12: note: possibly throwing constructor declared here W w; -// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: construction of 'w' with static storage duration may throw an exception that cannot be caught -// CHECK-MESSAGES: 25:3: note: possibly throwing constructor declared here +// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: initialization of 'w' with static storage duration may throw an exception that cannot be caught +// CHECK-MESSAGES: 24:3: note: possibly throwing constructor declared here +X x1(S{}); +// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: initialization of 'x1' with static storage duration may throw an exception that cannot be caught +// CHECK-MESSAGES: 4:3: note: possibly throwing constructor declared here +X x2; +// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: initialization of 'x2' with static storage duration may throw an exception that cannot be caught +// CHECK-MESSAGES: 4:3: note: possibly throwing constructor declared here +Y y; +// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: initialization of 'y' with static storage duration may throw an exception that cannot be caught +// CHECK-MESSAGES: 31:8: note: possibly throwing constructor declared here +Z z; + +int i = f(); +// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: initialization of 'i' with static storage duration may throw an exception that cannot be caught +// CHECK-MESSAGES: 39:5: note: possibly throwing function declared here +int j = g(); +// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: initialization of 'j' with static storage duration may throw an exception that cannot be caught +// CHECK-MESSAGES: 40:5: note: possibly throwing function declared here +int k = h(); +int l = some_bad_func(); +// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: initialization of 'l' with static storage duration may throw an exception that cannot be caught +// CHECK-MESSAGES: 44:3: note: possibly throwing function declared here +int m = some_good_func(); + thread_local S s3; -// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: construction of 's3' with thread_local storage duration may throw an exception that cannot be caught +// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: initialization of 's3' with thread_local storage duration may throw an exception that cannot be caught thread_local T t3; // ok thread_local U u3; -// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: construction of 'u3' with thread_local storage duration may throw an exception that cannot be caught +// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: initialization of 'u3' with thread_local storage duration may throw an exception that cannot be caught thread_local V v3("v"); -// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: construction of 'v3' with thread_local storage duration may throw an exception that cannot be caught +// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: initialization of 'v3' with thread_local storage duration may throw an exception that cannot be caught thread_local W w3; -// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: construction of 'w3' with thread_local storage duration may throw an exception that cannot be caught +// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: initialization of 'w3' with thread_local storage duration may throw an exception that cannot be caught void f(S s1, T t1, U u1, V v1, W w1) { // ok, ok, ok, ok, ok S s2; // ok @@ -72,44 +120,36 @@ namespace { S s; -// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: construction of 's' with static storage duration may throw an exception that cannot be caught [cert-err58-cpp] +// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: initialization of 's' with static storage duration may throw an exception that cannot be caught [cert-err58-cpp] // CHECK-MESSAGES: 4:3: note: possibly throwing constructor declared here T t; // ok U u; -// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: construction of 'u' with static storage duration may throw an exception that cannot be caught +// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: initialization of 'u' with static storage duration may throw an exception that cannot be caught // CHECK-MESSAGES: 12:3: note: possibly throwing constructor declared here V v("v"); -// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: construction of 'v' with static storage duration may throw an exception that cannot be caught +// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: initialization of 'v' with static storage duration may throw an exception that cannot be caught // CHECK-MESSAGES: 16:12: note: possibly throwing constructor declared here W w; -// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: construction of 'w' with static storage duration may throw an exception that cannot be caught -// CHECK-MESSAGES: 25:3: note: possibly throwing constructor declared here +// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: initialization of 'w' with static storage duration may throw an exception that cannot be caught +// CHECK-MESSAGES: 24:3: note: possibly throwing constructor declared here thread_local S s3; -// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: construction of 's3' with thread_local storage duration may throw an exception that cannot be caught +// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: initialization of 's3' with thread_local storage duration may throw an exception that cannot be caught thread_local T t3; // ok thread_local U u3; -// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: construction of 'u3' with thread_local storage duration may throw an exception that cannot be caught +// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: initialization of 'u3' with thread_local storage duration may throw an exception that cannot be caught thread_local V v3("v"); -// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: construction of 'v3' with thread_local storage duration may throw an exception that cannot be caught +// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: initialization of 'v3' with thread_local storage duration may throw an exception that cannot be caught thread_local W w3; -// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: construction of 'w3' with thread_local storage duration may throw an exception that cannot be caught +// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: initialization of 'w3' with thread_local storage duration may throw an exception that cannot be caught }; class Statics { - static S s; - // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: construction of 's' with static storage duration may throw an exception that cannot be caught [cert-err58-cpp] - // CHECK-MESSAGES: 4:3: note: possibly throwing constructor declared here + static S s; // warn when initialized static T t; // ok - static U u; - // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: construction of 'u' with static storage duration may throw an exception that cannot be caught - // CHECK-MESSAGES: 12:3: note: possibly throwing constructor declared here - static V v; - // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: construction of 'v' with static storage duration may throw an exception that cannot be caught - // CHECK-MESSAGES: 16:12: note: possibly throwing constructor declared here - static W w; - // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: construction of 'w' with static storage duration may throw an exception that cannot be caught - // CHECK-MESSAGES: 25:3: note: possibly throwing constructor declared here + static U u; // warn when initialized + static V v; // warn when initialized + static W w; // warn when initialized void f(S s, T t, U u, V v) { S s2; // ok @@ -133,15 +173,15 @@ }; S Statics::s; -// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: construction of 's' with static storage duration may throw an exception that cannot be caught [cert-err58-cpp] +// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: initialization of 's' with static storage duration may throw an exception that cannot be caught [cert-err58-cpp] // CHECK-MESSAGES: 4:3: note: possibly throwing constructor declared here T Statics::t; U Statics::u; -// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: construction of 'u' with static storage duration may throw an exception that cannot be caught +// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: initialization of 'u' with static storage duration may throw an exception that cannot be caught // CHECK-MESSAGES: 12:3: note: possibly throwing constructor declared here V Statics::v("v"); -// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: construction of 'v' with static storage duration may throw an exception that cannot be caught +// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: initialization of 'v' with static storage duration may throw an exception that cannot be caught // CHECK-MESSAGES: 16:12: note: possibly throwing constructor declared here W Statics::w; -// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: construction of 'w' with static storage duration may throw an exception that cannot be caught -// CHECK-MESSAGES: 25:3: note: possibly throwing constructor declared here +// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: initialization of 'w' with static storage duration may throw an exception that cannot be caught +// CHECK-MESSAGES: 24:3: note: possibly throwing constructor declared here