Skip to content

Commit fc0ea8c

Browse files
committed
upstream patch CppInterOp#880
From Vassil: compiler-research/CppInterOp#880
1 parent d3cdb55 commit fc0ea8c

5 files changed

Lines changed: 92 additions & 31 deletions

File tree

interpreter/CppInterOp/lib/CppInterOp/CppInterOp.cpp

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3668,30 +3668,8 @@ void GetIncludePaths(std::vector<std::string>& IncludePaths, bool withSystem,
36683668
IncludePaths.push_back(i);
36693669
}
36703670

3671-
namespace {
3672-
3673-
class clangSilent {
3674-
public:
3675-
clangSilent(clang::DiagnosticsEngine& diag) : fDiagEngine(diag) {
3676-
fOldDiagValue = fDiagEngine.getSuppressAllDiagnostics();
3677-
fDiagEngine.setSuppressAllDiagnostics(true);
3678-
}
3679-
3680-
~clangSilent() { fDiagEngine.setSuppressAllDiagnostics(fOldDiagValue); }
3681-
3682-
protected:
3683-
clang::DiagnosticsEngine& fDiagEngine;
3684-
bool fOldDiagValue;
3685-
};
3686-
} // namespace
3687-
36883671
int Declare(compat::Interpreter& I, const char* code, bool silent) {
3689-
if (silent) {
3690-
clangSilent diagSuppr(I.getSema().getDiagnostics());
3691-
return I.declare(code);
3692-
}
3693-
3694-
return I.declare(code);
3672+
return I.declare(code, silent);
36953673
}
36963674

36973675
int Declare(const char* code, bool silent) {

interpreter/CppInterOp/lib/CppInterOp/CppInterOpInterpreter.h

Lines changed: 55 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,8 @@ class Interpreter {
199199
std::unique_ptr<IOContext> io_context;
200200
bool outOfProcess;
201201

202+
clang::IgnoringDiagConsumer ignoring_consumer;
203+
202204
public:
203205
Interpreter(std::unique_ptr<clang::Interpreter> CI,
204206
std::unique_ptr<IOContext> ctx = nullptr, bool oop = false)
@@ -391,30 +393,76 @@ class Interpreter {
391393
return nullptr;
392394
}
393395

394-
CompilationResult declare(const std::string& input,
396+
CompilationResult declare(const std::string& input, bool silent = false,
395397
clang::PartialTranslationUnit** PTU = nullptr) {
396-
return process(input, /*Value=*/nullptr, PTU);
398+
return process(input, /*Value=*/nullptr, silent, PTU);
397399
}
398400

399-
///\brief Maybe transform the input line to implement cint command line
401+
/// A very lightweight RAII switcher. It manages diagnostic silencing
402+
/// and provides a unified interface for handling LLVM Errors.
403+
class SilentScope {
404+
bool m_is_silent;
405+
clang::DiagnosticsEngine& m_diags;
406+
clang::DiagnosticConsumer* m_oldClient;
407+
bool m_oldShouldOwn;
408+
409+
public:
410+
explicit SilentScope(Interpreter& I, bool silent)
411+
: m_is_silent(silent), m_diags(I.getSema().getDiagnostics()) {
412+
if (m_is_silent) {
413+
m_oldShouldOwn = m_diags.ownsClient();
414+
if (m_oldShouldOwn)
415+
m_oldClient = m_diags.takeClient().release();
416+
else
417+
m_oldClient = m_diags.getClient();
418+
// Ensure ignoring_consumer is accessible (friend or public)
419+
m_diags.setClient(&I.ignoring_consumer, /*ShouldOwnClient=*/false);
420+
}
421+
}
422+
423+
~SilentScope() {
424+
// Only restore if we actually swapped the client
425+
if (m_is_silent) {
426+
m_diags.setClient(m_oldClient, m_oldShouldOwn);
427+
}
428+
}
429+
430+
// Explicitly non-copyable
431+
SilentScope(const SilentScope&) = delete;
432+
SilentScope& operator=(const SilentScope&) = delete;
433+
434+
/// Consumes or logs the error based on the scope's silence setting.
435+
void handleOrConsume(llvm::Error err, const char* msg) {
436+
if (!err)
437+
return; // Safety check for "success" errors
438+
439+
if (m_is_silent)
440+
llvm::consumeError(std::move(err));
441+
else
442+
llvm::logAllUnhandledErrors(std::move(err), llvm::errs(), msg);
443+
}
444+
};
445+
/// Maybe transform the input line to implement cint command line
400446
/// semantics (declarations are global) and compile to produce a module.
401447
///
402448
CompilationResult process(const std::string& input, clang::Value* V = 0,
449+
bool silent = false,
403450
clang::PartialTranslationUnit** PTU = nullptr,
404451
bool disableValuePrinting = false) {
452+
SilentScope MaySilence(*this, silent);
405453
auto PTUOrErr = Parse(input);
406454
if (!PTUOrErr) {
407-
llvm::logAllUnhandledErrors(PTUOrErr.takeError(), llvm::errs(),
408-
"Failed to parse via ::process:");
455+
MaySilence.handleOrConsume(PTUOrErr.takeError(),
456+
"Failed to parse via ::process:");
409457
return Interpreter::kFailure;
410458
}
411459

412460
if (PTU)
413461
*PTU = &*PTUOrErr;
414462

415463
if (auto Err = Execute(*PTUOrErr)) {
416-
llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(),
417-
"Failed to execute via ::process:");
464+
MaySilence.handleOrConsume(std::move(Err),
465+
"Failed to execute via ::process:");
418466
return Interpreter::kFailure;
419467
}
420468
return Interpreter::kSuccess;

interpreter/CppInterOp/unittests/CMakeLists.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,13 @@ function(add_cppinterop_unittest name)
4141
${ARGN}
4242
)
4343
add_executable(${name} EXCLUDE_FROM_ALL ${ARG_UNPARSED_ARGUMENTS})
44+
if(NOT LLVM_ENABLE_RTTI)
45+
if(MSVC)
46+
target_compile_options(${name} PRIVATE "/GR-")
47+
else()
48+
target_compile_options(${name} PRIVATE "-fno-rtti")
49+
endif()
50+
endif()
4451
add_dependencies(CppInterOpUnitTests ${name})
4552
target_include_directories(${name} PUBLIC ${CMAKE_CURRENT_BINARY_DIR} ${GTEST_INCLUDE_DIR})
4653
set_property(TARGET ${name} PROPERTY RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})

interpreter/CppInterOp/unittests/CppInterOp/InterpreterTest.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,34 @@ TYPED_TEST(CPPINTEROP_TEST_MODE, Interpreter_EmscriptenExceptionHandling) {
199199
EXPECT_TRUE(Cpp::Process(tryCatchCode) == 0);
200200
}
201201

202+
TYPED_TEST(CPPINTEROP_TEST_MODE, Silent_Declare_Behavior) {
203+
auto* I = TestFixture::CreateInterpreter();
204+
ASSERT_TRUE(I);
205+
206+
EXPECT_FALSE(Cpp::Declare("int valid_var = 42;", /*silent=*/true));
207+
208+
// Should produce output
209+
{
210+
testing::internal::CaptureStderr();
211+
// Intentionally broken code: "int x = ;"
212+
bool success = Cpp::Declare("int broken_syntax = ;", /*silent=*/false);
213+
std::string output = testing::internal::GetCapturedStderr();
214+
EXPECT_TRUE(success);
215+
EXPECT_FALSE(output.empty()) << "We expect to see a Clang error message\n";
216+
}
217+
218+
// Should NOT produce output
219+
{
220+
testing::internal::CaptureStderr();
221+
// Intentionally broken code
222+
bool success = Cpp::Declare("invalid_type error_var = 0;", /*silent=*/true);
223+
std::string output = testing::internal::GetCapturedStderr();
224+
EXPECT_TRUE(success);
225+
EXPECT_TRUE(output.empty())
226+
<< "Silent Declare leaked an error to stderr: " << output;
227+
}
228+
}
229+
202230
TYPED_TEST(CPPINTEROP_TEST_MODE, Interpreter_CreateInterpreter) {
203231
auto* I = TestFixture::CreateInterpreter();
204232
EXPECT_TRUE(I);

interpreter/CppInterOp/unittests/CppInterOp/Utils.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ void TestUtils::GetAllTopLevelDecls(
7272
}
7373
#else
7474
PartialTranslationUnit *T = nullptr;
75-
Interp->process(code, /*Value*/nullptr, &T);
75+
Interp->process(code, /*Value*/ nullptr, /*silent=*/false, &T);
7676
for (auto *D : T->TUPart->decls()) {
7777
if (filter_implicitGenerated && D->isImplicit())
7878
continue;

0 commit comments

Comments
 (0)