1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
|
//===- unittests/Interpreter/InterpreterExceptionTest.cpp -----------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// Unit tests for Clang's Interpreter library.
//
//===----------------------------------------------------------------------===//
#include "clang/Interpreter/Interpreter.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclGroup.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/Version.h"
#include "clang/Config/config.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ExecutionEngine/Orc/LLJIT.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/TargetSelect.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
// Disable LSan for this test.
// FIXME: Re-enable once we can assume GCC 13.2 or higher.
// https://llvm.org/github.com/llvm/llvm-project/issues/67586.
#if LLVM_ADDRESS_SANITIZER_BUILD || LLVM_HWADDRESS_SANITIZER_BUILD
#include <sanitizer/lsan_interface.h>
LLVM_ATTRIBUTE_USED int __lsan_is_turned_off() { return 1; }
#endif
#if defined(_AIX) || defined(__MVS__)
#define CLANG_INTERPRETER_PLATFORM_CANNOT_CREATE_LLJIT
#endif
using namespace clang;
namespace {
using Args = std::vector<const char *>;
static std::unique_ptr<Interpreter>
createInterpreter(const Args &ExtraArgs = {},
DiagnosticConsumer *Client = nullptr) {
Args ClangArgs = {"-Xclang", "-emit-llvm-only"};
ClangArgs.insert(ClangArgs.end(), ExtraArgs.begin(), ExtraArgs.end());
auto CB = clang::IncrementalCompilerBuilder();
CB.SetCompilerArgs(ClangArgs);
auto CI = cantFail(CB.CreateCpp());
if (Client)
CI->getDiagnostics().setClient(Client, /*ShouldOwnClient=*/false);
return cantFail(clang::Interpreter::create(std::move(CI)));
}
#ifdef CLANG_INTERPRETER_PLATFORM_CANNOT_CREATE_LLJIT
TEST(InterpreterExceptionTest, DISABLED_CatchException) {
#else
TEST(InterpreterExceptionTest, CatchException) {
#endif
llvm::llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
llvm::InitializeNativeTarget();
llvm::InitializeNativeTargetAsmPrinter();
{
auto J = llvm::orc::LLJITBuilder().create();
if (!J) {
// The platform does not support JITs.
// Using llvm::consumeError will require typeinfo for ErrorInfoBase, we
// can avoid that by going via the C interface.
LLVMConsumeError(llvm::wrap(J.takeError()));
GTEST_SKIP();
}
}
#define Stringify(s) Stringifyx(s)
#define Stringifyx(s) #s
// We define a custom exception to avoid #include-ing the <exception> header
// which would require this test to know about the libstdc++ location.
// its own header file.
#define CUSTOM_EXCEPTION \
struct custom_exception { \
custom_exception(const char *Msg) : Message(Msg) {} \
const char *Message; \
};
CUSTOM_EXCEPTION;
std::string ExceptionCode = Stringify(CUSTOM_EXCEPTION);
ExceptionCode +=
R"(
extern "C" int printf(const char*, ...);
static void ThrowerAnError(const char* Name) {
throw custom_exception(Name);
}
extern "C" int throw_exception() {
try {
ThrowerAnError("To be caught in JIT");
} catch (const custom_exception& E) {
printf("Caught: '%s'\n", E.Message);
} catch (...) {
printf("Unknown exception\n");
}
ThrowerAnError("To be caught in binary");
return 0;
}
)";
std::unique_ptr<Interpreter> Interp = createInterpreter();
// FIXME: Re-enable the excluded target triples.
const clang::CompilerInstance *CI = Interp->getCompilerInstance();
const llvm::Triple &Triple = CI->getASTContext().getTargetInfo().getTriple();
// FIXME: ARM fails due to `Not implemented relocation type!`
if (Triple.isARM())
GTEST_SKIP();
// FIXME: libunwind on darwin is broken, see PR49692.
if (Triple.isOSDarwin() && (Triple.getArch() == llvm::Triple::aarch64 ||
Triple.getArch() == llvm::Triple::aarch64_32))
GTEST_SKIP();
llvm::cantFail(Interp->ParseAndExecute(ExceptionCode));
testing::internal::CaptureStdout();
auto ThrowException =
llvm::cantFail(Interp->getSymbolAddress("throw_exception"))
.toPtr<int (*)()>();
EXPECT_ANY_THROW(ThrowException());
std::string CapturedStdOut = testing::internal::GetCapturedStdout();
EXPECT_EQ(CapturedStdOut, "Caught: 'To be caught in JIT'\n");
}
} // end anonymous namespace
|