Skip to content

Commit 227fff9

Browse files
authored
Merge branch 'main' into Remove-cling-1.0-support
2 parents 8df3f8d + 0e399f1 commit 227fff9

File tree

5 files changed

+122
-25
lines changed

5 files changed

+122
-25
lines changed

.github/actions/Build_and_Test_cppyy/action.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,9 @@ runs:
121121
else
122122
SUPPRESSION_FILE="../etc/${CLANG_INTERPRETER}${CLANG_VERSION}-valgrind.supp"
123123
fi
124+
export IS_VALGRIND=true
124125
valgrind --show-error-list=yes --error-exitcode=1 --track-origins=yes --gen-suppressions=all --suppressions="${SUPPRESSION_FILE}" --suppressions=../etc/valgrind-cppyy-cling.supp python -m pytest -m "not xfail" -sv -ra --ignore=test_leakcheck.py
126+
unset IS_VALGRIND
125127
fi
126128
export RETCODE=+$?
127129
echo ::endgroup::

include/CppInterOp/CppInterOp.h

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -601,15 +601,26 @@ CPPINTEROP_API void GetOperator(TCppScope_t scope, Operator op,
601601
std::vector<TCppFunction_t>& operators,
602602
OperatorArity kind = kBoth);
603603

604-
/// Creates an instance of the interpreter we need for the various interop
605-
/// services.
604+
/// Creates an owned instance of the interpreter we need for the various interop
605+
/// services and pushes it onto a stack.
606606
///\param[in] Args - the list of arguments for interpreter constructor.
607607
///\param[in] CPPINTEROP_EXTRA_INTERPRETER_ARGS - an env variable, if defined,
608608
/// adds additional arguments to the interpreter.
609+
///\returns nullptr on failure.
609610
CPPINTEROP_API TInterp_t
610611
CreateInterpreter(const std::vector<const char*>& Args = {},
611612
const std::vector<const char*>& GpuArgs = {});
612613

614+
/// Deletes an instance of an interpreter.
615+
///\param[in] I - the interpreter to be deleted, if nullptr, deletes the last.
616+
///\returns false on failure or if \c I is not tracked in the stack.
617+
CPPINTEROP_API bool DeleteInterpreter(TInterp_t I = nullptr);
618+
619+
/// Activates an instance of an interpreter to handle subsequent API requests
620+
///\param[in] I - the interpreter to be activated.
621+
///\returns false on failure.
622+
CPPINTEROP_API bool ActivateInterpreter(TInterp_t I);
623+
613624
/// Checks which Interpreter backend was CppInterOp library built with (Cling,
614625
/// Clang-REPL, etcetera). In practice, the selected interpreter should not
615626
/// matter, since the library will function in the same way.

include/clang/Interpreter/CppInterOp.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@
22
#define CLANG_CPPINTEROP_H
33

44
#include "CppInterOp/CppInterOp.h"
5+
#if defined(_MSC_VER)
6+
#pragma message( \
7+
"#include <clang/Interpreter/CppInterOp.h> is deprecated; use #include <CppInterOp/CppInterOp.h")
8+
#else
59
#warning \
610
"#include <clang/Interpreter/CppInterOp.h> is deprecated; use #include <CppInterOp/CppInterOp.h"
11+
#endif
712

813
#endif // CLANG_CPPINTEROP_H

lib/CppInterOp/CppInterOp.cpp

Lines changed: 61 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,18 @@
4646
#include "llvm/ADT/StringRef.h"
4747
#include "llvm/Demangle/Demangle.h"
4848
#include "llvm/Support/Casting.h"
49+
#include "llvm/Support/CommandLine.h"
4950
#include "llvm/Support/Debug.h"
5051
#include "llvm/Support/raw_os_ostream.h"
5152

5253
#include <algorithm>
54+
#include <cassert>
5355
#include <iterator>
5456
#include <map>
57+
#include <memory>
5558
#include <set>
5659
#include <sstream>
60+
#include <stack>
5761
#include <string>
5862

5963
// Stream redirect.
@@ -71,30 +75,29 @@
7175
#include <unistd.h>
7276
#endif // WIN32
7377

74-
#include <stack>
75-
7678
namespace Cpp {
7779

7880
using namespace clang;
7981
using namespace llvm;
8082
using namespace std;
8183

82-
// Flag to indicate ownership when an external interpreter instance is used.
83-
static bool OwningSInterpreter = true;
84-
static compat::Interpreter* sInterpreter = nullptr;
85-
// Valgrind complains about __cxa_pure_virtual called when deleting
86-
// llvm::SectionMemoryManager::~SectionMemoryManager as part of the dtor chain
87-
// of the Interpreter.
88-
// This might fix the issue https://reviews.llvm.org/D107087
89-
// FIXME: For now we just leak the Interpreter.
90-
struct InterpDeleter {
91-
~InterpDeleter() = default;
92-
} Deleter;
84+
struct InterpreterInfo {
85+
compat::Interpreter* Interpreter = nullptr;
86+
bool isOwned = true;
87+
88+
// Valgrind complains about __cxa_pure_virtual called when deleting
89+
// llvm::SectionMemoryManager::~SectionMemoryManager as part of the dtor
90+
// chain of the Interpreter.
91+
// This might fix the issue https://reviews.llvm.org/D107087
92+
// FIXME: For now we just leak the Interpreter.
93+
~InterpreterInfo() = default;
94+
};
95+
static llvm::SmallVector<InterpreterInfo, 8> sInterpreters;
9396

9497
static compat::Interpreter& getInterp() {
95-
assert(sInterpreter &&
98+
assert(!sInterpreters.empty() &&
9699
"Interpreter instance must be set before calling this!");
97-
return *sInterpreter;
100+
return *sInterpreters.back().Interpreter;
98101
}
99102
static clang::Sema& getSema() { return getInterp().getCI()->getSema(); }
100103
static clang::ASTContext& getASTContext() { return getSema().getASTContext(); }
@@ -2930,19 +2933,54 @@ TInterp_t CreateInterpreter(const std::vector<const char*>& Args /*={}*/,
29302933
Args[NumArgs + 1] = nullptr;
29312934
llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args.get());
29322935
}
2933-
// FIXME: Enable this assert once we figure out how to fix the multiple
2934-
// calls to CreateInterpreter.
2935-
// assert(!sInterpreter && "Interpreter already set.");
2936-
sInterpreter = I;
2936+
2937+
sInterpreters.push_back({I, /*isOwned=*/true});
2938+
29372939
return I;
29382940
}
29392941

2940-
TInterp_t GetInterpreter() { return sInterpreter; }
2942+
bool DeleteInterpreter(TInterp_t I /*=nullptr*/) {
2943+
if (!I) {
2944+
sInterpreters.pop_back();
2945+
return true;
2946+
}
2947+
2948+
auto* found =
2949+
std::find_if(sInterpreters.begin(), sInterpreters.end(),
2950+
[&I](const auto& Info) { return Info.Interpreter == I; });
2951+
if (found == sInterpreters.end())
2952+
return false; // failure
2953+
2954+
sInterpreters.erase(found);
2955+
return true;
2956+
}
2957+
2958+
bool ActivateInterpreter(TInterp_t I) {
2959+
if (!I)
2960+
return false;
2961+
2962+
auto* found =
2963+
std::find_if(sInterpreters.begin(), sInterpreters.end(),
2964+
[&I](const auto& Info) { return Info.Interpreter == I; });
2965+
if (found == sInterpreters.end())
2966+
return false;
2967+
2968+
if (std::next(found) != sInterpreters.end()) // if not already last element.
2969+
std::rotate(found, found + 1, sInterpreters.end());
2970+
2971+
return true; // success
2972+
}
2973+
2974+
TInterp_t GetInterpreter() {
2975+
if (sInterpreters.empty())
2976+
return nullptr;
2977+
return sInterpreters.back().Interpreter;
2978+
}
29412979

29422980
void UseExternalInterpreter(TInterp_t I) {
2943-
assert(!sInterpreter && "sInterpreter already in use!");
2944-
sInterpreter = static_cast<compat::Interpreter*>(I);
2945-
OwningSInterpreter = false;
2981+
assert(sInterpreters.empty() && "sInterpreter already in use!");
2982+
sInterpreters.push_back(
2983+
{static_cast<compat::Interpreter*>(I), /*isOwned=*/false});
29462984
}
29472985

29482986
void AddSearchPath(const char* dir, bool isUser, bool prepend) {

unittests/CppInterOp/InterpreterTest.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,47 @@ TEST(InterpreterTest, Evaluate) {
8080
EXPECT_FALSE(HadError) ;
8181
}
8282

83+
TEST(InterpreterTest, DeleteInterpreter) {
84+
auto* I1 = Cpp::CreateInterpreter();
85+
auto* I2 = Cpp::CreateInterpreter();
86+
auto* I3 = Cpp::CreateInterpreter();
87+
EXPECT_TRUE(I1 && I2 && I3) << "Failed to create interpreters";
88+
89+
EXPECT_EQ(I3, Cpp::GetInterpreter()) << "I3 is not active";
90+
91+
EXPECT_TRUE(Cpp::DeleteInterpreter(nullptr));
92+
EXPECT_EQ(I2, Cpp::GetInterpreter());
93+
94+
auto* I4 = reinterpret_cast<void*>(static_cast<std::uintptr_t>(~0U));
95+
EXPECT_FALSE(Cpp::DeleteInterpreter(I4));
96+
97+
EXPECT_TRUE(Cpp::DeleteInterpreter(I1));
98+
EXPECT_EQ(I2, Cpp::GetInterpreter()) << "I2 is not active";
99+
}
100+
101+
TEST(InterpreterTest, ActivateInterpreter) {
102+
EXPECT_FALSE(Cpp::ActivateInterpreter(nullptr));
103+
auto* Cpp14 = Cpp::CreateInterpreter({"-std=c++14"});
104+
auto* Cpp17 = Cpp::CreateInterpreter({"-std=c++17"});
105+
auto* Cpp20 = Cpp::CreateInterpreter({"-std=c++20"});
106+
107+
EXPECT_TRUE(Cpp14 && Cpp17 && Cpp20);
108+
EXPECT_TRUE(Cpp::Evaluate("__cplusplus") == 202002L)
109+
<< "Failed to activate C++20";
110+
111+
auto* UntrackedI = reinterpret_cast<void*>(static_cast<std::uintptr_t>(~0U));
112+
EXPECT_FALSE(Cpp::ActivateInterpreter(UntrackedI));
113+
114+
EXPECT_TRUE(Cpp::ActivateInterpreter(Cpp14));
115+
EXPECT_TRUE(Cpp::Evaluate("__cplusplus") == 201402L);
116+
117+
Cpp::DeleteInterpreter(Cpp14);
118+
EXPECT_EQ(Cpp::GetInterpreter(), Cpp20);
119+
120+
EXPECT_TRUE(Cpp::ActivateInterpreter(Cpp17));
121+
EXPECT_TRUE(Cpp::Evaluate("__cplusplus") == 201703L);
122+
}
123+
83124
TEST(InterpreterTest, Process) {
84125
#ifdef _WIN32
85126
GTEST_SKIP() << "Disabled on Windows. Needs fixing.";

0 commit comments

Comments
 (0)