Skip to content

Commit

Permalink
Support std::uncaught_exceptions().
Browse files Browse the repository at this point in the history
  • Loading branch information
tmadden committed Sep 19, 2020
1 parent 14e84de commit 66ebb9e
Show file tree
Hide file tree
Showing 9 changed files with 78 additions and 4 deletions.
36 changes: 36 additions & 0 deletions src/alia/common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,42 @@ class function_view<Return(Args...)> final
}
};

// uncaught_exception_detector is a utility for detecting whether or not an
// object is being destructed due to an uncaught exception. It uses
// std::uncaught_exceptions() if available and std::uncaught_exception() if
// not.
#if __cplusplus >= 201703L
struct uncaught_exception_detector
{
uncaught_exception_detector()
{
base_exception_count_ = std::uncaught_exceptions();
}

bool
detect()
{
return base_exception_count_ != std::uncaught_exceptions();
}

private:
int base_exception_count_;
};
#else
struct uncaught_exception_detector
{
uncaught_exception_detector()
{
}

bool
detect()
{
return std::uncaught_exception();
}
};
#endif

} // namespace alia

#endif
2 changes: 1 addition & 1 deletion src/alia/flow/data_graph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ scoped_data_block::end()

// If GC is enabled, record which named blocks were used and clear out
// the unused ones.
if (traversal.gc_enabled && !std::uncaught_exception())
if (traversal.gc_enabled && !exception_detector_.detect())
{
traversal.active_block->named_blocks = traversal.used_named_blocks;
delete_named_block_ref_list(traversal.predicted_named_block);
Expand Down
1 change: 1 addition & 0 deletions src/alia/flow/data_graph.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ struct scoped_data_block : noncopyable

private:
data_traversal* traversal_;
uncaught_exception_detector exception_detector_;
// old state
data_block* old_active_block_;
named_block_ref_node* old_predicted_named_block_;
Expand Down
2 changes: 1 addition & 1 deletion src/alia/flow/macros.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ loop_block::~loop_block()
// iteration (and, indirectly, all subsequent iterations), but since the
// destructor is being invoked, there won't be a next iteration, which
// means we should clear out that block.
if (!std::uncaught_exception())
if (!exception_detector_.detect())
clear_data_block(*block_);
}
void
Expand Down
1 change: 1 addition & 0 deletions src/alia/flow/macros.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ struct loop_block : noncopyable
private:
data_traversal* traversal_;
data_block* block_;
uncaught_exception_detector exception_detector_;
};

struct event_dependent_if_block : noncopyable
Expand Down
3 changes: 2 additions & 1 deletion src/alia/flow/object_trees.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ struct scoped_tree_cacher
}
~scoped_tree_cacher()
{
if (!std::uncaught_exception())
if (!exception_detector_.detect())
end();
}

Expand Down Expand Up @@ -324,6 +324,7 @@ struct scoped_tree_cacher
bool content_traversal_required_;
captured_id content_id_;
tree_node<Object>** predecessor_;
uncaught_exception_detector exception_detector_;
};

} // namespace alia
Expand Down
2 changes: 1 addition & 1 deletion src/alia/flow/try_catch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ try_block::operator<<(function_view<void()> body)

try_block::~try_block()
{
if (uncaught_ && !std::uncaught_exception())
if (uncaught_ && !exception_detector_.detect())
{
mark_dirty_component(ctx_);
data_->uncaught = true;
Expand Down
1 change: 1 addition & 0 deletions src/alia/flow/try_catch.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ struct try_block

context ctx_;
try_block_data* data_;
uncaught_exception_detector exception_detector_;
bool uncaught_;
};

Expand Down
34 changes: 34 additions & 0 deletions unit_tests/common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,37 @@ TEST_CASE("is_invocable", "[common]")
!alia::is_invocable<decltype(f), int, int, std::string>::value,
"too many arguments");
}

struct uncaught_exception_tester
{
uncaught_exception_tester(bool* result) : result(result)
{
}

~uncaught_exception_tester()
{
*result = detector.detect();
}

bool* result;
uncaught_exception_detector detector;
};

TEST_CASE("uncaught_exception_detector", "[common]")
{
bool detected = false;
try
{
uncaught_exception_tester tester(&detected);
throw nullptr;
}
catch (...)
{
}
REQUIRE(detected);

{
uncaught_exception_tester tester(&detected);
}
REQUIRE(!detected);
}

0 comments on commit 66ebb9e

Please sign in to comment.