mirror of
https://github.com/Gericom/teak-llvm.git
synced 2025-06-19 19:45:40 -04:00

Summary: Finally, we are here! Analyzes OpenMP Structured Blocks and checks that no exception escapes out of the Structured Block it was thrown in. As per the OpenMP specification, structured block is an executable statement, possibly compound, with a single entry at the top and a single exit at the bottom. Which means, ``throw`` may not be used to to 'exit' out of the structured block. If an exception is not caught in the same structured block it was thrown in, the behaviour is undefined / implementation defined, the program will likely terminate. Reviewers: JonasToth, aaron.ballman, baloghadamsoftware, gribozavr Reviewed By: aaron.ballman, gribozavr Subscribers: mgorny, xazax.hun, rnkovacs, guansong, jdoerfert, cfe-commits, ABataev Tags: #clang-tools-extra, #openmp, #clang Differential Revision: https://reviews.llvm.org/D59466 llvm-svn: 356802
85 lines
3.3 KiB
C++
85 lines
3.3 KiB
C++
//===--- ExceptionEscapeCheck.cpp - clang-tidy ----------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "ExceptionEscapeCheck.h"
|
|
#include "clang/AST/ASTContext.h"
|
|
#include "clang/AST/OpenMPClause.h"
|
|
#include "clang/AST/Stmt.h"
|
|
#include "clang/AST/StmtOpenMP.h"
|
|
#include "clang/ASTMatchers/ASTMatchFinder.h"
|
|
#include "clang/ASTMatchers/ASTMatchers.h"
|
|
#include "clang/ASTMatchers/ASTMatchersMacros.h"
|
|
|
|
using namespace clang::ast_matchers;
|
|
|
|
namespace clang {
|
|
namespace tidy {
|
|
namespace openmp {
|
|
|
|
ExceptionEscapeCheck::ExceptionEscapeCheck(StringRef Name,
|
|
ClangTidyContext *Context)
|
|
: ClangTidyCheck(Name, Context),
|
|
RawIgnoredExceptions(Options.get("IgnoredExceptions", "")) {
|
|
llvm::SmallVector<StringRef, 8> FunctionsThatShouldNotThrowVec,
|
|
IgnoredExceptionsVec;
|
|
|
|
llvm::StringSet<> IgnoredExceptions;
|
|
StringRef(RawIgnoredExceptions).split(IgnoredExceptionsVec, ",", -1, false);
|
|
llvm::transform(IgnoredExceptionsVec, IgnoredExceptionsVec.begin(),
|
|
[](StringRef S) { return S.trim(); });
|
|
IgnoredExceptions.insert(IgnoredExceptionsVec.begin(),
|
|
IgnoredExceptionsVec.end());
|
|
Tracer.ignoreExceptions(std::move(IgnoredExceptions));
|
|
Tracer.ignoreBadAlloc(true);
|
|
}
|
|
|
|
void ExceptionEscapeCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
|
|
Options.store(Opts, "IgnoredExceptions", RawIgnoredExceptions);
|
|
}
|
|
|
|
void ExceptionEscapeCheck::registerMatchers(MatchFinder *Finder) {
|
|
// Don't register the check if OpenMP is not enabled; the OpenMP pragmas are
|
|
// completely ignored then, so no OpenMP entires will be present in the AST.
|
|
if (!getLangOpts().OpenMP)
|
|
return;
|
|
// Similarly, if C++ Exceptions are not enabled, nothing to do.
|
|
if (!getLangOpts().CPlusPlus || !getLangOpts().CXXExceptions)
|
|
return;
|
|
|
|
Finder->addMatcher(ompExecutableDirective(
|
|
unless(isStandaloneDirective()),
|
|
hasStructuredBlock(stmt().bind("structured-block")))
|
|
.bind("directive"),
|
|
this);
|
|
}
|
|
|
|
void ExceptionEscapeCheck::check(const MatchFinder::MatchResult &Result) {
|
|
const auto *Directive =
|
|
Result.Nodes.getNodeAs<OMPExecutableDirective>("directive");
|
|
assert(Directive && "Expected to match some OpenMP Executable directive.");
|
|
const auto *StructuredBlock =
|
|
Result.Nodes.getNodeAs<Stmt>("structured-block");
|
|
assert(StructuredBlock && "Expected to get some OpenMP Structured Block.");
|
|
|
|
if (Tracer.analyze(StructuredBlock).getBehaviour() !=
|
|
utils::ExceptionAnalyzer::State::Throwing)
|
|
return; // No exceptions have been proven to escape out of the struc. block.
|
|
|
|
// FIXME: We should provide more information about the exact location where
|
|
// the exception is thrown, maybe the full path the exception escapes.
|
|
|
|
diag(Directive->getBeginLoc(),
|
|
"an exception thrown inside of the OpenMP '%0' region is not caught in "
|
|
"that same region")
|
|
<< getOpenMPDirectiveName(Directive->getDirectiveKind());
|
|
}
|
|
|
|
} // namespace openmp
|
|
} // namespace tidy
|
|
} // namespace clang
|