llvm-project/clang-tools-extra/clang-tidy/cert/StaticObjectExceptionCheck.cpp
Aaron Ballman dda6290f16 Fix a false-positive with cert-err58-cpp.
If a variable is declared constexpr then its initializer needs to be a constant expression, and thus, cannot throw. This check is about not throwing exceptions before main() runs, and so it doesn't apply if the initializer cannot throw. This silences the diagnostic when initializing a constexpr variable and fixes PR35457.

llvm-svn: 347745
2018-11-28 11:57:13 +00:00

61 lines
2.2 KiB
C++

//===--- StaticObjectExceptionCheck.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 "StaticObjectExceptionCheck.h"
#include "../utils/Matchers.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
using namespace clang::ast_matchers;
namespace clang {
namespace tidy {
namespace cert {
void StaticObjectExceptionCheck::registerMatchers(MatchFinder *Finder) {
if ((!getLangOpts().CPlusPlus) || (!getLangOpts().CXXExceptions))
return;
// Match any static or thread_local variable declaration that has an
// initializer that can throw.
Finder->addMatcher(
varDecl(anyOf(hasThreadStorageDuration(), hasStaticStorageDuration()),
unless(anyOf(isConstexpr(), hasAncestor(functionDecl()))),
anyOf(hasDescendant(cxxConstructExpr(hasDeclaration(
cxxConstructorDecl(unless(isNoThrow())).bind("func")))),
hasDescendant(cxxNewExpr(hasDeclaration(
functionDecl(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<VarDecl>("var");
const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>("func");
diag(VD->getLocation(),
"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);
SourceLocation FuncLocation = Func->getLocation();
if (FuncLocation.isValid()) {
diag(FuncLocation,
"possibly throwing %select{constructor|function}0 declared here",
DiagnosticIDs::Note)
<< (isa<CXXConstructorDecl>(Func) ? 0 : 1);
}
}
} // namespace cert
} // namespace tidy
} // namespace clang