Skip to content

Re-raise R callback errors by value, not via std::exception_ptr (#3, part 1/2) - #4

Merged
mattfidler merged 2 commits into
mainfrom
issue-3
Oct 27, 2026
Merged

mattfidler merged 2 commits into
mainfrom
issue-3

Conversation

@mattfidler

@mattfidler mattfidler commented Oct 27, 2026 •

Copy link
Copy Markdown
Member

Part 1 of 2 for #3 (CRAN r-devel-linux-x86_64-fedora-clang test failures).

Problem

On CRAN's fedora-clang (clang + libc++), three tests failed with c++ exception (unknown reason):
test-minqa.R:122, test-steihaug.R:55, test-steihaug.R:114. All three go through the same path: the R callbacks in bobyqa()/newuoa()/steihaug() captured the error with std::current_exception() and re-raised it after the solver unwound via std::rethrow_exception(). On that toolchain the rethrown object no longer matched Rcpp's catch clauses (not even std::exception), so it fell into catch (...).

Fix

New src/r_callback_error.h (RCallbackError) stores the error by value: the Rcpp unwind token (held in an RObject, so it stays protected), an interrupt flag, or the what() message. Once the solver has returned, it throws a fresh Rcpp::LongjumpException / InterruptedException / Rcpp::exception. The original R condition still reaches the caller unchanged through the unwind token.

Tests now also check that a custom condition class survives (expect_error(..., class = "myErr")) for newuoa, bobyqa, steihaug (fn) and steihaug (hessvec).

Version bumped to 0.2.1 with a NEWS entry.

Verification

  • devtools::test(): 293 pass (gcc), and the same with a clang build.
  • I couldn't reproduce the libc++ failure itself locally (no libc++ installed). The fix removes the exception_ptr path that all three failures share.

Next in stack: #5 (OpenMP thread throttling).

🤖 Generated with Claude Code

On CRAN's fedora-clang (libc++) errors from R callbacks in bobyqa(),
newuoa() and steihaug() surfaced as 'c++ exception (unknown reason)'
after std::rethrow_exception. Store the error (unwind token, interrupt
or message) by value and throw a fresh exception instead (#3).
@codecov

codecov Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 92.00%. Comparing base (97db23b) to head (72e82f9).

Additional details and impacted files
@@            Coverage Diff             @@
##             main       #4      +/-   ##
==========================================
+ Coverage   91.97%   92.00%   +0.03%     
==========================================
  Files          25       26       +1     
  Lines        3899     3914      +15     
==========================================
+ Hits         3586     3601      +15     
  Misses        313      313              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

The INTERRUPT and NONE cases of rethrow() cannot be reached from tests
(Rcpp delivers R interrupts as LongjumpException, and callers rethrow
only after failed()), which dropped codecov/project on #4.
@mattfidler
mattfidler added this pull request to stack #6 October 27, 2026 21:01
@mattfidler
mattfidler merged commit 4a77ec2 into main Oct 27, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant